Despliegue manual de sitios web estáticos
Netlify es una plataforma de hosting y automatización orientada a sitios estáticos y aplicaciones frontend modernas. Permite desplegar proyectos de forma simple, ya sea conectando un repositorio o subiendo los archivos manualmente, sin necesidad de configurar servidores.
En este artículo aprenderás a publicar un proyecto en netlify subiendo los archivos de forma manual.
Iniciar sesión en Netlify
Netlify permite iniciar sesión de forma rápida mediante proveedores externos como GitHub, GitLab, Bitbucket o Google.
Este método facilita la integración directa con repositorios, integración que abordaremos en otro artículo.
Cuando inicias sesión por primera vez, la plataforma te permite configurar algunas preferencias. Al finalizar, solo debes desplazarte hasta el botón Continue to deploy.
El siguiente paso es omitir la pantalla que muestra las opciones para desplegar el primer proyecto.
Una vez autenticado, tendrás acceso al panel de control para crear y administrar tus sitios.
Desplegar un sitio de forma manual en Netlify
Netlify también permite desplegar un sitio de forma manual, sin necesidad de conectar un repositorio.
El despliegue manual es ideal para proyectos simples o sitios estáticos ya compilados (HTML, CSS y JavaScript).
Ejemplo de los archivos que vamos a subir para el despliegue:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mis Certificados</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="container">
<header>
<h1>Mis Certificados</h1>
<p class="subtitle">Una colección de mis logros y certificaciones profesionales obtenidas a lo largo de mi carrera.</p>
</header>
<div class="filters">
<button class="filter-btn active" data-filter="all">Todos</button>
<button class="filter-btn" data-filter="tecnologia">Tecnología</button>
<button class="filter-btn" data-filter="desarrollo">Desarrollo</button>
<button class="filter-btn" data-filter="diseño">Diseño</button>
<button class="filter-btn" data-filter="negocios">Negocios</button>
<button class="filter-btn" data-filter="idiomas">Idiomas</button>
</div>
<div class="certificates-grid" id="certificates-container">
<!-- Certificados se cargarán aquí con JavaScript -->
</div>
<footer>
<p>© <span id="current-year"></span> Mi Portafolio de Certificados</p>
<p>Total de certificados: <span id="certificate-count">0</span></p>
</footer>
</div>
<!-- Modal para vista detallada -->
<div class="modal" id="certificate-modal">
<div class="modal-content">
<div class="close-modal" id="close-modal">×</div>
<div class="modal-body" id="modal-body">
<!-- Contenido del modal se cargará con JavaScript -->
</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
// Datos de los certificados
const certificates = [
{
id: 1,
title: "Desarrollo Web Full Stack",
issuer: "Coursera",
date: "Junio 2023",
description: "Certificación completa en desarrollo web full stack, incluyendo tecnologías frontend y backend, bases de datos y despliegue de aplicaciones.",
tags: ["tecnologia", "desarrollo"],
category: "tecnologia",
icon: "fas fa-laptop-code"
},
{
id: 2,
title: "Diseño UX/UI Avanzado",
issuer: "Google",
date: "Marzo 2023",
description: "Curso avanzado de diseño de experiencia de usuario e interfaz de usuario, incluyendo investigación, prototipado y pruebas de usabilidad.",
tags: ["diseño", "ux", "ui"],
category: "diseño",
icon: "fas fa-palette"
},
{
id: 3,
title: "JavaScript Moderno ES6+",
issuer: "Udemy",
date: "Enero 2023",
description: "Dominio de las características modernas de JavaScript, incluyendo ES6+, promesas, async/await y patrones de diseño.",
tags: ["tecnologia", "desarrollo"],
category: "tecnologia",
icon: "fab fa-js-square"
},
{
id: 4,
title: "Inglés Profesional C1",
issuer: "Cambridge University",
date: "Diciembre 2022",
description: "Certificación de nivel C1 (Avanzado) de inglés según el Marco Común Europeo de Referencia para las lenguas.",
tags: ["idiomas", "inglés"],
category: "idiomas",
icon: "fas fa-language"
},
{
id: 5,
title: "Gestión de Proyectos Ágiles",
issuer: "Scrum.org",
date: "Octubre 2022",
description: "Certificación en metodologías ágiles y Scrum para la gestión eficiente de proyectos de desarrollo de software.",
tags: ["negocios", "gestión"],
category: "negocios",
icon: "fas fa-tasks"
},
{
id: 6,
title: "React.js Avanzado",
issuer: "Meta",
date: "Agosto 2022",
description: "Curso avanzado de React.js que cubre hooks, context API, renderizado del lado del servidor y patrones avanzados.",
tags: ["tecnologia", "desarrollo"],
category: "desarrollo",
icon: "fab fa-react"
},
{
id: 7,
title: "Diseño Gráfico Digital",
issuer: "Adobe",
date: "Mayo 2022",
description: "Certificación en herramientas de diseño gráfico digital, incluyendo Photoshop, Illustrator y After Effects.",
tags: ["diseño", "gráfico"],
category: "diseño",
icon: "fas fa-paint-brush"
},
{
id: 8,
title: "Análisis de Datos con Python",
issuer: "IBM",
date: "Febrero 2022",
description: "Especialización en análisis de datos utilizando Python, pandas, numpy y visualización con matplotlib y seaborn.",
tags: ["tecnologia", "datos"],
category: "tecnologia",
icon: "fas fa-chart-line"
}
];
// Elementos del DOM
const certificatesContainer = document.getElementById('certificates-container');
const filterButtons = document.querySelectorAll('.filter-btn');
const modal = document.getElementById('certificate-modal');
const closeModal = document.getElementById('close-modal');
const modalBody = document.getElementById('modal-body');
const certificateCount = document.getElementById('certificate-count');
const currentYear = document.getElementById('current-year');
// Estado de filtro activo
let activeFilter = 'all';
// Inicializar la página
function init() {
// Establecer el año actual
currentYear.textContent = new Date().getFullYear();
// Mostrar todos los certificados
displayCertificates(certificates);
// Agregar eventos a los botones de filtro
filterButtons.forEach(button => {
button.addEventListener('click', () => {
// Remover clase activa de todos los botones
filterButtons.forEach(btn => btn.classList.remove('active'));
// Agregar clase activa al botón clickeado
button.classList.add('active');
// Actualizar filtro activo
activeFilter = button.getAttribute('data-filter');
// Filtrar certificados
filterCertificates(activeFilter);
});
});
// Cerrar modal al hacer clic en la X
closeModal.addEventListener('click', () => {
modal.style.display = 'none';
});
// Cerrar modal al hacer clic fuera del contenido
modal.addEventListener('click', (e) => {
if (e.target === modal) {
modal.style.display = 'none';
}
});
}
// Mostrar certificados en el grid
function displayCertificates(certificatesToShow) {
certificatesContainer.innerHTML = '';
certificateCount.textContent = certificatesToShow.length;
certificatesToShow.forEach(cert => {
const card = document.createElement('div');
card.className = 'certificate-card';
card.dataset.id = cert.id;
card.dataset.category = cert.category;
card.innerHTML = `
<div class="certificate-img">
<i class="${cert.icon}"></i>
</div>
<div class="certificate-info">
<h3 class="certificate-title">${cert.title}</h3>
<div class="certificate-issuer">
<i class="fas fa-building"></i>
${cert.issuer}
</div>
<div class="certificate-date">
<i class="far fa-calendar-alt"></i>
${cert.date}
</div>
<div class="certificate-tags">
${cert.tags.map(tag => `<span class="tag">${tag}</span>`).join('')}
</div>
</div>
`;
// Agregar evento para abrir modal
card.addEventListener('click', () => openCertificateModal(cert));
certificatesContainer.appendChild(card);
});
}
// Filtrar certificados por categoría
function filterCertificates(filter) {
if (filter === 'all') {
displayCertificates(certificates);
} else {
const filteredCertificates = certificates.filter(cert =>
cert.category === filter || cert.tags.includes(filter)
);
displayCertificates(filteredCertificates);
}
}
// Abrir modal con detalles del certificado
function openCertificateModal(certificate) {
modalBody.innerHTML = `
<div class="modal-img">
<i class="${certificate.icon}" style="font-size: 6rem; color: #4a6491;"></i>
</div>
<h2 class="modal-title">${certificate.title}</h2>
<div class="modal-details">
<div class="detail-item">
<span class="detail-label">Institución</span>
<span>${certificate.issuer}</span>
</div>
<div class="detail-item">
<span class="detail-label">Fecha de emisión</span>
<span>${certificate.date}</span>
</div>
<div class="detail-item">
<span class="detail-label">Categoría</span>
<span>${certificate.category.charAt(0).toUpperCase() + certificate.category.slice(1)}</span>
</div>
<div class="detail-item">
<span class="detail-label">ID de certificado</span>
<span>#${certificate.id.toString().padStart(3, '0')}</span>
</div>
</div>
<div class="modal-description">
<p>${certificate.description}</p>
</div>
<div class="certificate-tags" style="margin-top: 20px;">
${certificate.tags.map(tag => `<span class="tag">${tag}</span>`).join('')}
</div>
`;
modal.style.display = 'flex';
}
// Inicializar cuando el DOM esté cargado
document.addEventListener('DOMContentLoaded', init);
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background-color: #f8f9fa;
color: #333;
line-height: 1.6;
/* Fondo con imagen elegante */
background-image: url('background.jpeg');
background-size: cover;
background-position: center;
background-attachment: fixed;
background-repeat: no-repeat;
position: relative;
min-height: 100vh;
}
/* Capa overlay para mejorar legibilidad */
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(135deg, rgba(248, 249, 250, 0.62) 0%, rgba(248, 249, 250, 0.85) 100%);
z-index: -1;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
position: relative;
z-index: 1;
}
/* Header */
header {
text-align: center;
padding: 40px 0;
background: linear-gradient(135deg, rgba(44, 62, 80, 0.95), rgba(74, 100, 145, 0.95));
color: white;
border-radius: 10px;
margin-bottom: 40px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
backdrop-filter: blur(5px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
h1 {
font-size: 2.5rem;
margin-bottom: 10px;
font-weight: 300;
}
.subtitle {
font-size: 1.1rem;
opacity: 0.9;
max-width: 600px;
margin: 0 auto;
}
/* Filtros */
.filters {
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 30px;
}
.filter-btn {
padding: 10px 20px;
background-color: rgba(255, 255, 255, 0.9);
border: 1px solid rgba(221, 221, 221, 0.5);
border-radius: 50px;
cursor: pointer;
transition: all 0.3s ease;
font-weight: 500;
backdrop-filter: blur(5px);
}
.filter-btn:hover {
background-color: rgba(240, 240, 240, 0.95);
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.filter-btn.active {
background-color: rgba(44, 62, 80, 0.95);
color: white;
border-color: rgba(44, 62, 80, 0.8);
}
/* Grid de certificados */
.certificates-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 30px;
margin-bottom: 40px;
}
.certificate-card {
background-color: rgba(255, 255, 255, 0.95);
border-radius: 10px;
overflow: hidden;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
cursor: pointer;
border: 1px solid rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
}
.certificate-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
background-color: rgba(255, 255, 255, 0.98);
}
.certificate-img {
height: 200px;
background: linear-gradient(135deg, rgba(233, 236, 239, 0.9), rgba(206, 212, 218, 0.9));
display: flex;
align-items: center;
justify-content: center;
color: #4a6491;
position: relative;
overflow: hidden;
}
.certificate-img::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(45deg, transparent 30%, rgba(255, 255, 255, 0.3) 50%, transparent 70%);
animation: shine 3s infinite linear;
}
@keyframes shine {
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
}
.certificate-img img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.5s ease;
}
.certificate-card:hover .certificate-img img {
transform: scale(1.05);
}
.certificate-img i {
font-size: 4rem;
z-index: 1;
position: relative;
}
.certificate-info {
padding: 20px;
}
.certificate-title {
font-size: 1.2rem;
font-weight: 600;
margin-bottom: 8px;
color: #2c3e50;
}
.certificate-issuer {
color: #4a6491;
font-weight: 500;
margin-bottom: 10px;
display: flex;
align-items: center;
gap: 5px;
}
.certificate-date {
color: #6c757d;
font-size: 0.9rem;
margin-bottom: 15px;
display: flex;
align-items: center;
gap: 5px;
}
.certificate-tags {
display: flex;
flex-wrap: wrap;
gap: 5px;
}
.tag {
background-color: rgba(233, 236, 239, 0.8);
color: #495057;
padding: 4px 10px;
border-radius: 50px;
font-size: 0.8rem;
backdrop-filter: blur(5px);
}
/* Modal para vista detallada */
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.85);
z-index: 1000;
align-items: center;
justify-content: center;
padding: 20px;
backdrop-filter: blur(5px);
}
.modal-content {
background-color: rgba(255, 255, 255, 0.98);
border-radius: 10px;
max-width: 800px;
width: 100%;
max-height: 90vh;
overflow-y: auto;
position: relative;
box-shadow: 0 15px 40px rgba(0, 0, 0, 0.3);
border: 1px solid rgba(255, 255, 255, 0.2);
backdrop-filter: blur(20px);
}
.close-modal {
position: absolute;
top: 15px;
right: 20px;
font-size: 1.8rem;
color: #333;
cursor: pointer;
z-index: 10;
background: rgba(255, 255, 255, 0.9);
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
border: 1px solid rgba(0, 0, 0, 0.1);
}
.close-modal:hover {
background: rgba(44, 62, 80, 0.9);
color: white;
transform: rotate(90deg);
}
.modal-body {
padding: 30px;
}
.modal-img {
width: 100%;
height: 300px;
background: linear-gradient(135deg, rgba(233, 236, 239, 0.9), rgba(206, 212, 218, 0.9));
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 20px;
border-radius: 8px;
overflow: hidden;
position: relative;
}
.modal-img::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(45deg, transparent 30%, rgba(255, 255, 255, 0.2) 50%, transparent 70%);
animation: shine 3s infinite linear;
}
.modal-img img {
width: 100%;
height: 100%;
object-fit: contain;
z-index: 1;
position: relative;
}
.modal-title {
font-size: 1.8rem;
color: #2c3e50;
margin-bottom: 15px;
}
.modal-details {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 25px;
}
.detail-item {
display: flex;
flex-direction: column;
padding: 15px;
background-color: rgba(248, 249, 250, 0.7);
border-radius: 8px;
border: 1px solid rgba(0, 0, 0, 0.05);
}
.detail-label {
font-weight: 600;
color: #4a6491;
margin-bottom: 5px;
font-size: 0.9rem;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.modal-description {
line-height: 1.7;
color: #555;
padding: 20px;
background-color: rgba(248, 249, 250, 0.5);
border-radius: 8px;
border-left: 4px solid #4a6491;
}
/* Footer */
footer {
text-align: center;
padding: 20px 0;
color: #6c757d;
border-top: 1px solid rgba(233, 236, 239, 0.5);
margin-top: 40px;
background-color: rgba(255, 255, 255, 0.7);
border-radius: 10px;
backdrop-filter: blur(10px);
}
/* Responsive */
@media (max-width: 768px) {
.certificates-grid {
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
}
h1 {
font-size: 2rem;
}
.modal-body {
padding: 20px;
}
body {
background-attachment: scroll;
}
}
@media (max-width: 480px) {
.certificates-grid {
grid-template-columns: 1fr;
}
.filters {
justify-content: flex-start;
overflow-x: auto;
padding-bottom: 10px;
}
.modal-img {
height: 200px;
}
}
/* Animación de carga suave */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.certificate-card {
animation: fadeIn 0.5s ease forwards;
}
/* Desplazamiento suave */
html {
scroll-behavior: smooth;
}
Selecciona un archivo para ver su contenido
Desde el panel principal, solo debes arrastrar la carpeta del proyecto (con los archivos ya mencionados) al área indicada como “Drag and drop your site project here”.
Netlify se encargará automáticamente de subir los archivos y generar una URL pública para tu sitio.
Y eso es todo. Nuestro sitio web ya está en internet, con HTTPS habilitado, y lo único que debes hacer ahora es compartir tu URL.
En este caso, la dirección que nos proporciona Netlify es la siguiente:
https://storied-cajeta-59d0b0.netlify.app
Como puedes observar, se trata de una URL generada automáticamente, bastante larga y poco representativa de nuestro proyecto. Esto es totalmente normal en Netlify y no afecta en absoluto al funcionamiento del sitio.
Cambiar el nombre del sitio en Netlify
A continuación, veremos cómo personalizar el nombre del sitio para obtener una URL más limpia. En la pantalla anterior, presiona el botón de “Quick setup”.
Una vez dentro de la configuración rápida, puedes elegir un nuevo nombre para actualizar la URL del sitio. Al presionar Update site name, Netlify verificará automáticamente la disponibilidad del nombre.
Si el nombre elegido ya está en uso, la plataforma te lo notificará de inmediato:
Una vez tengas un nombre válido, presiona el botón de “update project name”:
Ahora contamos con una URL más amigable, disponible de forma inmediata para su acceso.
Con esto, hemos completado el despliegue manual en Netlify de forma exitosa. El sitio ya se encuentra disponible en línea y listo para ser accedido, lo que nos permite validar el resultado final antes de avanzar a configuraciones más avanzadas como dominios personalizados, variables de entorno o despliegues automatizados.


















