Creación de un documento web
● Introducción
- ◆ Iniciaremos con el esqueleto del documento en HTML.
- ◆ Aplicaremos el diseño CSS.
- ◆ Finalmente las funciones de JavaScript generando un proyecto integrado.
Absorbe el panorama general sin detenerte en los detalles técnicos; nos encargaremos de explicar a fondo cada tema a lo largo de los próximos ejercicios de manera progresiva.
● Video Tutorial
💻 Ver explicación en video de youtube.

● Carpetas y archivos
Paso 1
- ◆ Creamos una carpeta dentro del escritorio o en un espacio del disco que podamos ubicar.
- ◆ Abrimos Visual Studio Code y con File - Open Folder, abrimos dicha carpeta.
- ◆ Situándonos en el menú lateral izquierdo, aparece al lado del nombre de nuestra carpeta un menú con íconos, presionamos en el primero para generar el archivo index.html.
Paso 2 - Estructura base
Con las teclas “! + tab” o “! + enter” se genera la siguiente base:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
</html>
En la estructura base, como nuestro sitio web será en español, cambiamos el atributo lang=“en” de la etiqueta html por lang=“es”. Es útil para los lectores de pantallas y para los buscadores.
También en la etiqueta title, escribimos nuestro título y queda así:
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ejercicio Presentación</title>
</head>
<body>
</body>
</html>
Haciendo doble click desde el explorador de archivos a nuestro index.html podemos visualizar los cambios.
Solo aparecerá la pestaña superior con el título, porque no hemos escrito nada aún dentro del body.

● Estructura del documento
Paso 2
Dentro del body, iniciamos nuestro documento.
Tendremos 3 secciones principales
- ❖ Encabezado => header
- ❖ Sector Principal => main
- ❖ Pie de página => footer
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Ejercicio Presentación</title>
</head>
<body>
<header></header>
<main></main>
<footer></footer>
</body>
</html>
Iremos desarrolando de a uno.
● El Header
Paso 3
...
<body>
<header>
</header>
<main></main>
<footer></footer>
</body>
...
En un principio, en el header tendremos 2 partes:
- ❖ El logo => etiqueta a.
- ❖ El menu de navegación => etiqueta ul.
Pero como queremos que quede fija en la parte superior siempre, vamos a encerrar todo en una etiqueta nav.
...
<body>
<header>
<nav>
<a href="#">BricolajeWeb</a>
<ul>
<li><a href="">Inicio</a></li>
<li><a href="">Fundamentos</a></li>
<li><a href="">Cursos</a></li>
<li><a href="">Contacto</a></li>
</ul>
</nav>
</header>
<main></main>
<footer></footer>
</body>
...
En el explorador al recargar la página, se verá así:

● Estilos al Header
Paso 4
◆ Creamos desde el ícono “+” en el menú lateral derecho el archivo style.css.
◆ Le indicamos al index.html que tome los estilos de dicho archivo con la etiqueta:
<link rel="stylesheet" href="style.css">
La misma se escribe dentro del head

En el archivo style.css iniciamos con la configuración general:
*{
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
margin: 0;
padding: 0;
box-sizing: border-box;
text-decoration: none;
list-style: none;
color: currentColor;
}
y nos va a quedar así:

Si nos situamos sobre index.html con botón derecho, nos aparece la opción Show Preview, presionamos y nos aparecerá en el costado derecho, como se va viendo el documento a medida que lo desarrollamos.
(Previamente debimos haber agregado en Visual Studio Code la extensión “Live Preview” de Microsoft.)
Si agregamos la extensión Live Server, podemos visualizar el documento con sus cambios al instante desde Go Live, en el menú inferior.

Paso 5
Lo primero es enviar el logo hacia la izquierda y el menú de navegación a la derecha.
header nav{
display: flex;
justify-content:space-between;
align-items: center;
}

Alineamos los items de la etiqueta ul
header nav ul{
display:flex;
align-items: center;
gap:3rem;
}

Al logo le damos mayor tamaño y otro tipo de letra para que se distinga. Para que solo afecte la etiqueta a del logo y no a todos. A esa etiqueta, la identificamos con un id
<a href="#" id="logo">BricolajeWeb</a>
Entonces al ubicarla no ponemos solo la etiqueta sino su id
header nav a#logo{
font-family: fantasy;
font-size: 2rem;
font-weight: 400;
}
Quedaría asi:

● Contenedor
Paso 6
Primeramente estamos desarrollando el documento web para pantallas grandes (computadoras).
En próximos pasos desarrollaremos para tablets y celulares.
◆ Definimos una clase contenedor que aplicaremos en varias etiquetas, según vayamos necesitando.
.contenedor{
max-width: 1300px;
margin: 0 auto;
padding: 1rem 4rem;
}
Aplicamos esta clase en la etiqueta nav
<body>
<header>
<nav class="contenedor">
<a href="#" id="logo">BricolajeWeb</a>
<ul>
<li><a href="">Inicio</a></li>
<li><a href="">Fundamentos</a></li>
<li><a href="">Cursos</a></li>
<li><a href="">Contacto</a></li>
</ul>
</nav>
</header>
<main></main>
<footer></footer>
</body>

Y nos va quedando asi:

● Imagenes
- ◆ Creamos en este directorio una carpeta imágenes.
- ◆ Copiamos las imágenes que corresponden a este proyecto en su interior.
Paso 7
Ubicamos la imagen que deseamos aparezca en la pestaña superior del navegador web. (El favicon). La palabra favicon viene del inglés favorite icon, en español, Ícono favorito.
...
<head>
...
<link rel="shortcut icon" href="imagenes/icono-logo.svg" type="image/x-icon">
...
</head>

Paso 8
Ubicamos la imagen del logo en el encabezado (header)
...
<header>
<nav class="contenedor">
<a href="#" id="logo"><img src="imagenes/icono-logo.svg" alt=""><span>BricolajeWeb</span></a>
<ul>
<li><a href="">Inicio</a></li>
<li><a href="">Fundamentos</a></li>
<li><a href="">Cursos</a></li>
<li><a href="">Contacto</a></li>
</ul>
</nav>
</header>
...
Va a quedar así:

Debemos adaptar nuevamente el css. Lo corregimos:
header nav a#logo {
display: flex;
align-items: center;
gap:0.1rem
}
header nav a#logo img{
width: 1.8rem;
height: 1.8rem;
object-fit: contain;
}
header nav a#logo span{
font-family: fantasy;
font-size: 2rem;
font-weight: 400;
}

● Desarrollamos el main
Paso 9
El main va a tener 4 secciones, cada una de las cuales tendrá su id:
...
<main>
<section id="seccion1"></section>
<section id="seccion2"></section>
<section id="seccion3"></section>
<section id="seccion4"></section>
</main>
...
- Iniciaremos la primera, que tiene una imagen de fondo y otra en su centro frontal.
- La imagen de fondo se determina en el CSS y la de frente en el HTML
<main>
<section id="seccion1">
<img src="imagenes/logo-seccion1.png" alt="">
</section>
<section id="seccion2"></section>
<section id="seccion3"></section>
<section id="seccion4"></section>
</main>
section#seccion1{
min-height: 100vh;
display: grid;
place-items: center;
background: url('imagenes/seccion1.webp') no-repeat;
background-position: center;
background-size: cover;
}
Y nos va a quedar en el navegador renderizado lo siguiente:

● Responsivo
Pero hasta ahora, el documento no se adapta a distintos tamaños de pantalla. Solo a computadoras grandes.
● Paso 10
Volvemos al header y agregamos el menú hamburguesa, o menú 3 rayas.
...
<header>
<nav class="contenedor">
<a href="#" id="logo"><img src="imagenes/icono-logo.svg" alt=""><span>BricolajeWeb</span></a>
<ul>
<li><a href="">Inicio</a></li>
<li><a href="">Fundamentos</a></li>
<li><a href="">Cursos</a></li>
<li><a href="">Contacto</a></li>
</ul>
<button id="icono-menu">
<span></span>
<span></span>
<span></span>
</button>
</nav>
</header>
...
button#icono-menu{
width: 2rem;
height: 1rem;
background: none;
border: none;
display: flex;
flex-direction: column;
justify-content: space-between;
cursor: pointer;
}
button#icono-menu span{
height: 2px;
width: 100%;
background-color: currentColor;
}
Pero queremos que el ícono solamente aparezca en las pantallas pequeñas.
Y cuando aparece, al presionarlo, el menú de opciones aparezca abajo en bloques.
button#icono-menu{
width: 2rem;
height: 1rem;
background: none;
border: none;
display: none;
flex-direction: column;
justify-content: space-between;
cursor: pointer;
}
button#icono-menu span{
height: 2px;
width: 100%;
background-color: currentColor;
}
@media (max-width:768px) {
.contenedor{
padding: 1rem;
}
button#icono-menu{
display: flex;
}
header nav{
position: relative;
}
header nav ul{
position: absolute;
top:99%;
left:0;
right: 0;
padding: 1rem;
background-color: white;
display:inline-block;
border-top:1px solid lightgray;
border-bottom:1px solid lightgray;
}
header nav ul li{
margin: 1rem 0;
}
}
Observar cambios:


● Abrir y cerrar Menú
Paso 11
Para abrir y cerrar el menú usaremos javascript.
Primeramente en el css agregamos al menu de opciones una propiedad que lo cierra, clip-path.
Esta propiedad genera una figura geométrica y todo lo que está adentro se muestra y lo que está afuera se oculta.
Para ocultarlo, haremos un rectángulo sin altura, entonces no se va a mostrar nada. Luego al hacer click, le agregamos la propiedad activo que genera un rectángulo con el 100% de altura y muestra todo.


header nav ul{
position: absolute;
top:99%;
left:0;
right: 0;
padding: 1rem;
background-color: white;
display:inline-block;
border-top:1px solid lightgray;
border-bottom:1px solid lightgray;
/* cerrado */
clip-path: polygon(0 0, 100% 0, 100% 0, 0 0);
}
header nav ul.activo{
/* abierto */
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
}
Cerrado aparece así:

Creamos el archivo script.js y lo relacionamos con el index.html agrando la siguiente etiqueta en la parte inferior DENTRO DEL BODY.
...
<script src="script.js"></script>
...
<div style="margin:0 auto;"><img src="/imagenes-md/001-presentacion/imagen-20.png" alt="Pantallas grandes"></div>
En el script.js escribimos:
// Primero identificamos el ícono-menu y el menú de opciones.
const iconoMenu = document.getElementById('icono-menu');
// Previamente en el index.html le ponemos id=opciones a la etiqueta ul
const menuOpciones = document.getElementById('opciones');
/* Escribimos la sentencia que necesitamos:
Cuando el usuario hace click en el iconoMenu, el navegador buscar la etiqueta que tiene por id 'opciones' y en su lista de clase CSS, si está la clase activo, la elimina, y si no está la agrega.
Entonces al agregarle el clip-path: que genera un rectángulo con altura, se abre.
*/
iconoMenu.addEventListener('click',()=>{
menuOpciones.classList.toggle('activo');
});
// Cuando lleguemos al curso de javascript, comprenderemos mejor, esta sentencia.
Antes identificamos la etiqueta ul con el id
...
<ul id="opciones">
<li><a href="">Inicio</a></li>
<li><a href="">Fundamentos</a></li>
<li><a href="">Cursos</a></li>
<li><a href="">Contacto</a></li>
</ul>
...
Para que esa transición sea suave agregamos:
header nav ul{
position: absolute;
top:99%;
left:0;
right: 0;
padding: 1rem;
background-color: white;
display:inline-block;
border-top:1px solid lightgray;
border-bottom:1px solid lightgray;
/* cerrado */
clip-path: polygon(0 0, 100% 0, 100% 0, 0 0);
transition: 0.2s linear;
}
header nav ul.activo{
/* abierto */
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
}
● Sección 2
Paso 12
Lo primero es generar el html. Vamos a tener 2 partes dentro del contenedor ( para que guarde relación con el header):
<section id="seccion2">
<div class="contenedor">
<article></article>
<article></article>
</div>
</section>
Dentro de cada parte, tendremos una imagen y zona de detalle: En la primera imagen/detallle y en la segunda detalle/imagen porque por diseño decidimos que nos gusta así.
<section id="seccion2">
<div class="contenedor">
<article>
<div class="imagen">
<img src="imagenes/nosotros-1.png" alt="Imagen Nosotros 1">
</div>
<div class="detalle"></div>
</article>
<article>
<div class="detalle"></div>
<div class="imagen">
<img src="imagenes/nosotros-2.png" alt="Imagen Nosotros 1">
</div>
</article>
</div>
</section>
Dentro de cada detalle, tendremos un título, un párrafo y un link de redirección a otra zona:
<section id="seccion2">
<div class="contenedor">
<article>
<div class="imagen">
<img src="imagenes/nosotros-1.png" alt="Imagen Nosotros 1">
</div>
<div class="detalle">
<h3>Título 1</h3>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Id sequi tempora ipsa dignissimos eveniet. Quis beatae autem animi, reprehenderit totam voluptate fuga tenetur atque perspiciatis officia obcaecati veniam debitis optio?</p>
<a href="#seccion4">Saber Más</a>
</div>
</article>
<article>
<div class="detalle">
<h3>Título 2</h3>
<p>Lorem 2 ipsum dolor sit amet consectetur adipisicing elit. Id sequi tempora ipsa dignissimos eveniet. Quis beatae autem animi, reprehenderit totam voluptate fuga tenetur atque perspiciatis officia obcaecati veniam debitis optio?</p>
<a href="#seccion4">Saber Más</a>
</div>
<div class="imagen">
<img src="imagenes/nosotros-2.png" alt="Imagen Nosotros 1">
</div>
</article>
</div>
</section>
Dentro de las etiquetas, se escribe lo que cada uno necesite, en función de lo que el creador del documento web desee mostrar.
Para que se ordene, le damos estilo a las etiquetas:
En el style.css
section#seccion2 .contenedor article .imagen img{
width: 100%;
}
section#seccion2 .contenedor article{
display: flex;
align-items: center;
flex-wrap: wrap;
}
section#seccion2 .contenedor article .imagen,
section#seccion2 .contenedor article .detalle
{
flex:1 1 34rem;
}
Estas propiedades funcionan juntas, sino se escribe todo, no funciona.
- ❖ Darle flexibilidad a la imagen para que se adapte a su padre, por eso se determina que su ancho sea un porcentaje.
- ❖ Al padre le aplicamos la propiedad flex, que afecta a sus hijos. Los escribe uno al lado del otro.
- ❖ Con align-item se centran.
- ❖ Con flex-wrap:wrap; si no entran según el ancho (width) determinado al hijo (siguiente selector), se baja. Esto es útil para cuando la pantalla se achica según el dispositivo del que se trate.
- ❖ Con flex: 1 1 34rem; estamos fijando el ancho de los hijos, por eso separados por coma, detallamos el nombre de cada hijo usando una clase y no un id, debido a que tenemos 2 iguales. El id sirve solo cuando la etiqueta es única.
- ❖ Todo esto tiene relación con las propiedades escritas en la clase contenedor, porque fija el máximo posible. Si no se escribe un máximo de ancho, tampoco funciona.

También en algunos casos es necesario fijar un ancho mínimo a los hijos.
● Estilo al detalle
Paso 13
A continuación le aplicamos estilo a las etiquetas en el interior de la clase detalle.
section#seccion2 .contenedor article .detalle h3{
color: orangered;
font-size: 2rem;
}
section#seccion2 .contenedor article .detalle p{
margin: 1rem 0;
color: gray;
line-height: 1.8;
}
Para el botón, generamos una clase .btnque escribiremos debajo del .contenedor debido a que será algo que aplicaremos a todos los botones que querramos dibujar en nuestro documento, a modo de lograr uniformidad.
.btn{
background: linear-gradient(to right, orangered, orange);
color: white;
font-size: 1.1rem;
letter-spacing: 1px;
padding:1rem 2rem;
border-radius: 0.5rem;
box-shadow: 1px 1px 2px lightgray;
transition: 0.2s linear;
}
.btn:hover{
background: linear-gradient(to left, orangered, orange);
}
Recordamos aplicarlo en el index.html
<a href="#seccion4" class="btn">Saber Más</a>
Para que en tablets y celulares se acomode bien en el style.css agregamos:
section#seccion2 .contenedor article:last-child .detalle{
text-align: right;
}
@media (max-width:1300px) {
section#seccion2 .contenedor article:last-child{
flex-wrap: wrap-reverse;
}
}
El text-align a la derecha es un detalle de diseño, pero la media query que agregamos a partir de los 1300px es para que se acomode bien, sabiendo que a partir de esa medida, no se agrande la clase detalle, sino que se sitúa abajo de la imagen.
● Tipo de letra
● Paso 14
Antes de continuar con la sección 3, vamos a aprender a incorporar tipos de letras, también llamadas fuentes (font en inglés) de google-fonts.
Visitamos el sitio google-fonts
En la lupa superior, escribimos la letra buscada. En nuestro caso Sniglet
Seleccionamos GET FONT
Luego vamos al menú lateral derecho y presionamos en fonts
En la lupa escribimos Montserrat enter y luego GET FONT
Una vez elegidas ambas, vamos al botón de GET EMBED CODE
En:

Presionamos copy code y lo pegamos en el interior del head de nuestro index.html
...
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="imagenes/icono-logo.svg" type="image/x-icon">
<title>Ejercicio Presentación</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&family=Sniglet:wght@400;800&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
</head>
...
En el style.css efectuamos el siguiente cambio: En font-family borramos fantasy y escribimos tal cual se detalla abajo.
header nav a#logo span{
font-family: "Sniglet", system-ui;
font-size: 2rem;
font-weight: 400;
}
Hacemos lo mismo en el *{} aplicandolé la familia de letras que elegimos. Se puede elegir la que nos guste.
*{
font-family: "Montserrat", sans-serif;
margin: 0;
padding: 0;
box-sizing: border-box;
text-decoration: none;
list-style: none;
color: currentColor;
}
● Galería con Swiper
● Paso 15
La sección 3 desarrolla la escritura de una galería utilizando una librería (código ya desarrollado por otras personas) llamada swiper.
Esta librería tiene una sección gratis y otra paga. Usaremos la parte gratis.
Sirve como ejemplo para construir nuestro código y cuando es necesario usamos código desarrollado por otros, hasta que aprendamos a desarrollarlo nosotros mismos.
Primero escribimos nuestras etiquetas html que van a ser simples para concentrarnos en swiper. Tendrán un título, un párrafo y un borde redondeado.
Para contenerlas y poder aplicar swiper necesitamos varios div anidados.
<section id="seccion3">
<div class="contenedor swiper">
<div class="galeria">
<div class="swiper-wrapper">
Aquí van las tarjetas individuales una debajo de la otra.
</div>
</div>
</div>
</section>
Agregando las tarjetas queda así:
<section id="seccion3">
<div class="contenedor swiper">
<div class="galeria">
<div class="swiper-wrapper">
<div class="tarjeta swiper-slide">
<h3>Título 1</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Provident, sequi? Sint quae maiores atque sequi ut nihil recusandae velit vitae voluptate ducimus, odio doloremque, iusto exercitationem repellendus ad voluptas molestiae!</p>
</div>
<div class="tarjeta swiper-slide">
<h3>Título 2</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Provident, sequi? Sint quae maiores atque sequi ut nihil recusandae velit vitae voluptate ducimus, odio doloremque, iusto exercitationem repellendus ad voluptas molestiae!</p>
</div>
<div class="tarjeta swiper-slide">
<h3>Título 3</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Provident, sequi? Sint quae maiores atque sequi ut nihil recusandae velit vitae voluptate ducimus, odio doloremque, iusto exercitationem repellendus ad voluptas molestiae!</p>
</div>
<div class="tarjeta swiper-slide">
<h3>Título 4</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Provident, sequi? Sint quae maiores atque sequi ut nihil recusandae velit vitae voluptate ducimus, odio doloremque, iusto exercitationem repellendus ad voluptas molestiae!</p>
</div>
<div class="tarjeta swiper-slide">
<h3>Título 5</h3>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Provident, sequi? Sint quae maiores atque sequi ut nihil recusandae velit vitae voluptate ducimus, odio doloremque, iusto exercitationem repellendus ad voluptas molestiae!</p>
</div>
</div>
</div>
</div>
</section>
Es una galería a modo de presentación. Una vez implementada, se advertirá que es fácil de usar y con la práctica se hace más fácil aún.
Aplicamos estilo a las tarjetas. En el style.css
section#seccion3 .tarjeta{
/* propiedad provisoria- después se borra */
max-width: 30rem;
background-color: white;
border: 1px solid orangered;
border-radius: 0.5rem;
box-shadow: 2px 2px 4px lightgrey;
padding: 3rem;
margin: 0 auto;
text-align: center;
}
section#seccion3 .tarjeta h3{
color:orangered;
}
section#seccion3 .tarjeta p{
color:gray;
line-height: 1.8;
text-align: justify;
margin-top: 1rem;
}
Vamos a tener las tarjetas alineadas en el centro. Visitamos el sitio web de swiper
Rolamos hacia abajo hasta encontrar el cdn (Content Delivery Network o Red de Distribución de Contenido en español servicio gratuito de red de entrega de contenido) cuyo link copiamos y pegamos en el head y el script en el interior del body, en la parte inferior, pero siempre arriba de la etiqueta script que conecta nuestro script.js.

...
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="imagenes/icono-logo.svg" type="image/x-icon">
<title>Ejercicio Presentación</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&family=Sniglet:wght@400;800&display=swap" rel="stylesheet">
<link rel="stylesheet"href="https://cdn.jsdelivr.net/npm/swiper@12/swiper-bundle.min.css"/>
<link rel="stylesheet" href="style.css">
</head>
...
<body>
...
<footer></footer>
<script src="https://cdn.jsdelivr.net/npm/swiper@12/swiper-bundle.min.js"></script>
<script src="script.js"></script>
</body>
...
Agregamos la paginacion al index.html
<section id="seccion3">
<div class="contenedor swiper">
<div class="galeria">
<div class="swiper-wrapper">
...
</div>
<div class="swiper-pagination"></div>
</div>
</div>
</section>
En nuestro script.js agregamos lo siguiente : (fue sacado de los demos)
//Swiper
const swiper = new Swiper('.galeria', {
slidesPerView: 1,
spaceBetween: 10,
loop:true,
autoplay:{
delay: 2500,
disableOnInteraction: false,
},
pagination: {
el: '.swiper-pagination',
clickable: true,
},
breakpoints: {
640: {
slidesPerView: 1,
},
768: {
slidesPerView: 2,
},
1024: {
slidesPerView: 3,
},
},
});
En el style.css aplicamos las siguientes propiedades para mejorarlo:
section#seccion3 .galeria{
overflow-x: hidden;
margin: 2rem auto;
}
section#seccion3 .swiper-pagination-bullet-active{
background-color: orangered;
}
● Navegación interna
Paso 16
En las etiquetas llamadas anclas, debemos referenciar el href correspondiente, especificándole a que título queremos que se dija el scroll. Con el # solo, la página vuelve a cargar. Con #id, se dirije a la etiqueta con ese id. Entonces en el header completamos con:
...
<header>
<nav class="contenedor">
<a href="#" id="logo"><img src="imagenes/icono-logo.svg" alt=""><span>BricolajeWeb</span></a>
<ul id="opciones">
<li><a href="#seccion1">Inicio</a></li>
<li><a href="#seccion2">Fundamentos</a></li>
<li><a href="#seccion3">Cursos</a></li>
<li><a href="#seccion4">Contacto</a></li>
</ul>
<button id="icono-menu">
<span></span>
<span></span>
<span></span>
</button>
</nav>
</header>
...
Tenemos varios temas:
- ❖ Que el scroll sea suave.
- ❖ Que el encabezado quede fijo en la parte superior.
- ❖ Que la barra del scroll esté en sintonía con nuestros colores.
Scroll suave
En la parte superior del style.css, debajo del selector *{} escribimos:
html{
scroll-behavior: smooth;
scroll-padding-top: 5rem;
}
Encabezado fijo
En style.css agregamos
header{
position: sticky;
top:0;
left: 0;
width: 100%;
background: white;
}
A modo de detalle para mejorarlo, en el script.js podemos agregar:
window.addEventListener('scroll',()=>{
if (scrollY > 30){
document.body.classList.add('sombra');
}else{
document.body.classList.remove('sombra');
}
});
y en el style.css agregamos la clase .sombra
header{
position: sticky;
top:0;
left: 0;
width: 100%;
background: white;
}
body.sombra header{
box-shadow: 1px 1px 2px lightgray;
}
Para que al seleccionar una opción, el menú se cierre debemos quitarle la clase activo a la etiqueta ul
window.addEventListener('scroll',()=>{
document.querySelector('header nav ul').classList.remove('activo');
if (scrollY > 30){
document.body.classList.add('sombra');
}else{
document.body.classList.remove('sombra');
}
});
Estilos barra scroll
Para aplicar estilos generales se usa el selector ::, así agregamos en el style.css.
::-webkit-scrollbar{
width: 0.5rem;
}
::-webkit-scrollbar-track{
background-color: white;
}
::-webkit-scrollbar-thumb{
background-color: orangered;
border-radius: 2rem;
}
/* selección de texto dentro del documento*/
::selection{
background-color: orangered;
color: white;
}
● Íconos de información
Paso 17
Comenzamos como siempre, escribiendo el index.html. Vamos a tener un contenedor con 2 partes: la información y el formulario.
<section id="seccion4">
<div class="contenedor">
<article></article>
<form action=""></form>
</div>
</section>
En la etiqueta article, tendremos tres bloques con los mismos estilos, dentro de cada uno, habrá un ícono, un subtítulo y un dato.
<section id="seccion4">
<div class="contenedor">
<article>
<!-- un bloque -->
<div class="info">
<!-- ícono de font-awesome -->
<span class="material-symbols-outlined">home</span>
<div >
<h3>Domicilio</h3>
<p>Calle Lavenida 123, Ciudad, País</p>
</div>
</div>
<!-- otro bloque -->
<div class="info">
<span class="material-symbols-outlined">phone_in_talk</span>
<div >
<h3>Teléfono</h3>
<p>+99 123 - 123 456 789</p>
</div>
</div>
<!-- otro bloque -->
<div class="info">
<span class="material-symbols-outlined">mail</span>
<div >
<h3>Email</h3>
<p> info@empresa.com</p>
</div>
</div>
</article>
<form action=""></form>
</div>
</section>
Los íconos
<span class="material-symbols-outlined">home</span>
<span class="material-symbols-outlined">phone_in_talk</span>
<span class="material-symbols-outlined">mail</span>
Cada uno de esas etiquetas dibujarán un ícono, unicamente si agregamos en el head, el cdn de google icons, como con swiper y con google fonts. Visita este sitio para obtener el link de font awesome
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
Lo agregamos dentro del head.

En ese sitio web, seleccionamos el ícono Home por ejemplo.
Nos aparece un menú lateral derecho , donde haciendo scroll hacia abajo encontramos el link que va en el head.
Pero para que nos sirva para todos los íconos, le borramos la última parte hasta el signo & quedando:
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200" />
Haciendo scroll más abajo, encontramos la etiqueta que corresponde al ícono seleccionado, la cual la copiaremos en nuestro index.html

● Formulario
Paso 18
Desarrollamos el formulario en index.html.
...
<!-- Esta vez enviaremos el mensaje por whatsapp a un numero donde querramos recibir los mensajes -->
<form action="#"method="post" id="formWhatsApp">
<h3>Estemos en contacto</h3>
<div class="flex">
<input type="text" placeholder="Tu nombre" maxlength="30" class="input" id="nombre">
<input type="text" placeholder="Tu teléfono" maxlength="15" class="input" id="telefono">
</div>
<input type="text" placeholder="Tu email" maxlength="30" class="input" id="email">
<textarea placeholder="Tu mensaje" cols="30" rows="10" maxlength="1000" class="input" id="mensaje"></textarea>
<button type="submit" class="btn" id="btnEnviar">Enviar info</button>
</form>
...
Aplicamos los estilos de esta sección.
Primero el mismo sistema que usamos en la sección 2, pero esta vez el article tendrá un tamaño más chico que el formulario.
section#seccion4 .contenedor{
display:flex;
align-items: center;
flex-wrap: wrap;
gap:2rem;
}
section#seccion4 .contenedor article{
flex: 1 1 15rem;
padding:1rem;
}
section#seccion4 .contenedor form{
flex: 1 1 30rem;
}
Continuamos específicamente con los hijos del article.
section#seccion4 .contenedor article .info{
display:flex;
gap:1rem;
padding-top: 2rem;
}
section#seccion4 .contenedor article .info span{
height: 2.3rem;
width: 2.3rem;
line-height: 1.5;
background: orangered;
border-radius: 0.5rem;
text-align: center;
color:white;
}
section#seccion4 .contenedor article .info h3{
margin-bottom: 0.5rem;
color: currentColor;
}
section#seccion4 .contenedor article .info p{
color: gray;
font-size: 0.85rem;
line-height: 1.5;
}
Y con los hijos del formulario:
...
section#seccion4 .contenedor form{
flex: 1 1 30rem;
display:flex;
flex-direction: column;
gap:1rem;
}
...
section#seccion4 .contenedor form .flex{
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
gap:0.5rem
}
section#seccion4 .contenedor form .flex input{
flex:1 1 18rem;
}
section#seccion4 .contenedor form .input{
width: 100%;
outline: none;
border: none;
box-shadow: 0 0.1rem 0.5rem lightgray;
border-radius: 0.5rem;
padding: 1rem;
}
section#seccion4 .contenedor form button{
width: fit-content;
border: none;
cursor: pointer;
}
section#seccion4 input::placeholder{
color: gray;
}
section#seccion4 .contenedor form .input:focus{
border: 1px solid orangered;
}
Envío mensaje
Para enviar el mensaje necesitamos usar javascript.
const formulario = document.getElementById('formWhatsApp');
const inputNombre = document.getElementById('nombre');
const inputTelefono = document.getElementById('telefono');
const inputEmail = document.getElementById('email');
const inputMensaje = document.getElementById('mensaje');
const numeroWhatsApp = '5493510000000'; // Tu número
formulario.addEventListener('submit', (e) => {
e.preventDefault(); // Detiene el envío clásico del formulario
const nombre = inputNombre.value.trim();
const telefono = inputTelefono.value.trim();
const email = inputEmail.value.trim();
const mensaje = inputMensaje.value.trim();
if (nombre === '' || telefono === '' || email === '' || mensaje === '') {
alert('Por favor, completa todos los campos.');
return;
}
const textoMensaje = `Hola, soy ${nombre} mi telefono es ${telefono} y mi email ${email}. ${mensaje}`;
const textoCodificado = encodeURIComponent(textoMensaje);
// Redirección directa por JS
const urlWhatsApp = `https://wa.me/${numeroWhatsApp}?text=${textoCodificado}`;
window.open(urlWhatsApp, '_blank');
});
Primero identificamos las etiquetas del html que vamos a necesitar.
const formulario = document.getElementById('formWhatsApp');
const inputNombre = document.getElementById('nombre');
const inputTelefono = document.getElementById('telefono');
const inputEmail = document.getElementById('email');
const inputMensaje = document.getElementById('mensaje');
Luego, estamos atentos a que suceda el evento submit, es decir, cuando el usuario presiona “Enviar información”.
formulario.addEventListener('submit', (e) => {
e.preventDefault(); // Detiene el envío clásico del formulario
//Desarrollamos lo que se debe hacer con el formulario
});
Cuando se presiona un botón de tipo submit, se activa el formulario:
- ❖ Tomamos el valor de cada etiqueta ya identificada y le quitamos los espacios en blanco.
- ❖ Evaluamos si hay campos vacíos. En caso afirmativo, pedimos que se completen y salimos de la sentancia con return.
- ❖ Si está todo correcto, armamos una string con todas las palabras.
- ❖ Abrimos una nueva ventana con la url de whatsapp.
● Footer
Finalmente, escribimos el pie de página.
<footer>
<div class="contenedor">
Creado por   <strong><i>caterinaweb.net</i></strong>   2026
</div>
</footer>
footer{
background:linear-gradient(to right, orangered,orange);
padding: 0.3rem;
color: white;
text-align: center;
letter-spacing: 1px;
}
● Subirlo a la red
De esta manera finalizamos nuestro sitio web, solo queda subirlo a un servidor, para que cualquier persona pueda acceder a él.
Vamos a utilizar esta primera vez un servidor gratuito.
Una vez en el sitio web nos registramos.(Sign up) No se necesita tarjeta de crédito. Puede ser con nuestra cuenta de google o con un email y contraseña.
Una vez registrados, entramos con log in.
La primera vez vamos a donde dice “upload your projects” - “Drag and drop your folder here.”
- choose your folder -. Es decir elegir nuestra carpeta. Presionamos allí y se nos abre el explorador, seleccionamos la carpeta donde desarrollamos el proyecto y esperamos a que cargue.

La segunda vez, cuando ya tenemos un projecto, aparece el botón de Add new project y al presionar nos aparece nuevamente la opción para elegir una carpeta.
El sistema nos asigna un dominio automático que podemos utilizar, pero si lo deseamos, podemos comprar uno nuevo, usar uno que ya hayamos adquirido o simplemente, mejorar y cambiarlo por otro más fácil de recordar con la terminación .netlify.app gratis.


● Video Tutorial
Ver explicación en video de youtube