Advertisement
  1. Web Design
  2. CSS

Cómo crear una página estática para portafolio con CSS y JavaScript

Scroll to top
Read Time: 11 min

() translation by (you can also view the original English article)

En este tutorial utilizaremos todo el poder de flexbox y aprenderemos a crear una simple, pero atractiva página estática para portafolio en HTML. También crearemos un gráfico de columnas responsivas sin usar ninguna biblioteca externa de JavaScript, SVG, o el elemento canvas. ¡Únicamente con CSS!

Aquí está el proyecto que vamos a crear (haz clic en el enlace Skills [Habilidades] en la esquina superior):

Nota: Este tutorial asume que tienes algunos conocimientos de flexbox. Si estás comenzando, Anna Monus tiene una gran colección de guías para principiantes:

1. Inicia con el marcado de la página

El marcado de la página es bastante simple; una cabecera, un título, un enlace mailto y una sección:

1
<body class="position-fixed d-flex flex-column text-white bg-red">
2
  <header class="page-header">
3
    <nav class="d-flex justify-content-between">
4
      <a href="" class="logo">...</a>
5
      <ul class="d-flex">
6
        <li>
7
          <a href="">...</a>
8
        </li>
9
        <!-- possibly more list items here -->
10
      </ul>
11
    </nav>
12
  </header>
13
  <h1 class="position-absolute w-100 text-center heading">...</h1>
14
  <a class="position-absolute contact" href="">...</a>
15
  <section class="position-absolute d-flex align-items-center justify-content-center text-black bg-white skills-section" data-slideIn="to-top">
16
    <!-- content here -->
17
  </section>
18
</body>

Dentro de la sección, colocamos un botón de cierre y un elemento de envoltura con dos listas. Estas listas son responsables de crear el gráfico de columnas:

1
<section class="position-absolute d-flex align-items-center justify-content-center text-black bg-white skills-section" data-slideIn="to-top">
2
  <button class="position-absolute skills-close" aria-label="Close Skills Section"></button>
3
  <div class="d-flex chart-wrapper">
4
    <ul class="chart-levels">
5
      <li>Expert</li>
6
      <li>Advanced</li>
7
      <li>Intermediate</li>
8
      <li>Beginner</li>
9
      <li>Novice</li>
10
    </ul>
11
    <ul class="d-flex justify-content-around align-items-end flex-grow-1 text-center bg-black chart-skills">
12
      <li class="position-relative bg-red" data-height="80%">
13
        <span class="position-absolute w-100">CSS</span>
14
      </li>
15
      <li class="position-relative bg-red" data-height="60%">
16
        <span class="position-absolute w-100">HTML</span>
17
      </li>
18
      <li class="position-relative bg-red" data-height="68%">
19
        <span class="position-absolute w-100">JavaScript</span>
20
      </li>
21
      <li class="position-relative bg-red" data-height="52%">
22
        <span class="position-absolute w-100">Python</span>
23
      </li>
24
      <li class="position-relative bg-red" data-height="42%">
25
        <span class="position-absolute w-100">Ruby</span>
26
      </li>
27
    </ul>
28
  </div>
29
</section>

Nota: Más allá de las clases específicas de los elementos, nuestro marcado contiene un número de clases de utilidad (auxiliares). Usaremos esta metodología para mantener nuestro CSS lo más DRY (No te repitas, por sus siglas en inglés. También se le conoce como: Una vez y solo una) posible. No obstante, por razones de legibilidad, dentro del CSS no agruparemos las reglas comunes de CSS.

2. Define algunos estilos básicos

Cumpliendo con lo que acabamos de comentar, ahora especificamos algunas reglas de reinicio junto con una serie de clases auxiliares:

1
:root {
2
  --black: #1a1a1a;
3
  --white: #fff;
4
  --red: #e21838;
5
  --transition-delay: 0.85s;
6
  --transition-delay-step: 0.3s;
7
}
8
9
* {
10
  padding: 0;
11
  margin: 0;
12
}
13
14
ul {
15
  list-style: none;
16
}
17
18
a {
19
  text-decoration: none;
20
  color: inherit;
21
}
22
23
button {
24
  background: none;
25
  border: none;
26
  cursor: pointer;
27
  outline: none;
28
}
29
30
.d-flex {
31
  display: flex;
32
}
33
34
.flex-column {
35
  flex-direction: column;
36
}
37
38
.justify-content-center {
39
  justify-content: center;
40
}
41
42
.justify-content-between {
43
  justify-content: space-between;
44
}
45
46
.justify-content-around {
47
  justify-content: space-around;
48
}
49
50
.align-items-center {
51
  align-items: center;
52
}
53
54
.align-items-end {
55
  align-items: flex-end;
56
}
57
58
.flex-grow-1 {
59
  flex-grow: 1;
60
}
61
62
.w-100 {
63
  width: 100%;
64
}
65
66
.position-relative {
67
  position: relative;
68
}
69
70
.position-fixed {
71
  position: fixed;
72
}
73
74
.position-absolute {
75
  position: absolute;
76
}
77
78
.text-center {
79
  text-align: center;
80
}
81
82
.text-black {
83
  color: var(--black);
84
}
85
86
.text-white {
87
  color: var(--white);
88
}
89
90
.bg-black {
91
  background: var(--black);
92
}
93
94
.bg-white {
95
  background: var(--white);
96
}
97
98
.bg-red {
99
  background: var(--red);
100
}

Las nomenclaturas para nuestras clases auxiliares están inspiradas en los nombres de las clases de Bootstrap 4.

3. Estiliza el diseño de la página

El diseño de la página será tan simple como esto:

The page layoutThe page layoutThe page layout

Aquí están los requisitos del diseño:

  • La página debe ser a pantalla completa.
  • El logotipo se sitúa en la esquina superior izquierda de la página, el menú en la esquina superior derecha y el enlace mailto en la esquina inferior derecha.
  • El título está centrado de forma horizontal y vertical.
  • La sección que contiene el gráfico está inicialmente oculta (fuera de la pantalla).

Aquí están los estilos correspondientes para hacer todo esto:

1
body {
2
  top: 0;
3
  right: 0;
4
  bottom: 0;
5
  left: 0;
6
  font: 1rem/1.5 "Montserrat", sans-serif;
7
  overflow: hidden;
8
}
9
10
.page-header {
11
  padding: 20px;
12
  border-bottom: 1px solid #e93451;
13
}
14
15
.page-header li:not(:last-child) {
16
  margin-right: 20px;
17
}
18
19
.page-header .logo {
20
  font-size: 1.2rem;
21
  z-index: 1;
22
  transition: color 0.3s;
23
}
24
25
.window-opened .page-header .logo {
26
  color: var(--black);
27
  transition-delay: 0.8s;
28
}
29
30
.heading {
31
  top: 50%;
32
  left: 50%;
33
  transform: translate(-50%, -50%);
34
  font-size: 2.5rem;
35
}
36
37
.contact {
38
  bottom: 20px;
39
  right: 20px;
40
}
41
42
.skills-section {
43
  top: 0;
44
  right: 0;
45
  bottom: 0;
46
  left: 0;
47
  transform: translateX(100%);
48
}

El progreso hasta ahora

¡Esto es lo que hemos creado hasta el momento!

4. Alternando la sección

Como se comentó anteriormente, al principio la sección está oculta. Se hará visible con un agradable efecto deslizante cada vez que hagamos clic en el enlace del menú. Haremos esto añadiendo la clase window-opened al elemento body y alterando el CSS según sea necesario. De la misma manera, la sección desaparecerá tan pronto como hagamos clic en el botón de cerrar.

Como bonificación, nos daremos la facultad de establecer la dirección de la animación de deslizamiento. Podemos pasar el atributo personalizado data-slideIn a la sección que determinará la posición inicial de su animación. Los posibles valores de los atributos son: to-top, to-bottom, y to-right. De manera predeterminada, la sección aparece de derecha a izquierda.

Aquí están los estilos asociados:

1
.skills-section {
2
  top: 0;
3
  right: 0;
4
  bottom: 0;
5
  left: 0;
6
  transform: translateX(100%);
7
  transition: transform 1s;
8
}
9
10
.window-opened .skills-section {
11
  transform: none;
12
}
13
14
[data-slideIn="to-top"] {
15
  transform: translateY(100%);
16
}
17
18
[data-slideIn="to-bottom"] {
19
  transform: translateY(-100%);
20
}
21
22
[data-slideIn="to-right"] {
23
  transform: translateX(-100%);
24
}

Y el código JavaScript necesario para alternar su estado:

1
const skillsLink = document.querySelector(".page-header li:nth-child(1) a");
2
const skillsClose = document.querySelector(".skills-close");
3
const windowOpened = "window-opened";
4
5
skillsLink.addEventListener("click", (e) => {
6
  e.preventDefault();
7
  document.body.classList.toggle(windowOpened);
8
});
9
10
skillsClose.addEventListener("click", () => {
11
  document.body.classList.toggle(windowOpened);
12
});

4. Estiliza el gráfico

En este punto, veremos más de cerca el contenido de nuestra sección. Primero tenemos el botón de cierre situado en la parte superior derecha de la sección.

Aquí está su marcado:

1
  <button class="position-absolute skills-close" aria-label="Close Skills Section"></button>

Y sus estilos:

1
.skills-close {
2
  top: 20px;
3
  right: 20px;
4
  font-size: 2rem;
5
}

A continuación tenemos el gráfico en sí. También revisemos nuevamente su estructura:

1
<div class="d-flex chart-wrapper">
2
  <ul class="chart-levels">
3
    <li>Expert</li>
4
    ...
5
  </ul>
6
  
7
  <ul class="d-flex justify-content-around align-items-end flex-grow-1 text-center bg-black chart-skills">
8
    <li class="position-relative bg-red" data-height="80%">
9
      <span class="position-absolute w-100">CSS</span>
10
    </li>
11
    ...
12
  </ul>
13
</div>

Aquí están los puntos clave con respecto a este marcado:

  • Configuramos el elemento .chart-wrapper como un contenedor flexible con dos listas como elementos flexibles.
  • La segunda lista, que mide el conocimiento de una determinada habilidad, es en sí misma un contenedor flexible. Le damos flex-grow: 1 para crecer y ocupar todo el espacio disponible.

Las reglas iniciales de CSS para nuestro gráfico:

1
.chart-wrapper {
2
  width: calc(100% - 40px);
3
  max-width: 500px;
4
}
5
6
.chart-levels li {
7
  padding: 15px;
8
}

En este momento, veremos más de cerca los elementos de la segunda lista.

Puntos a recordar:

  • Todos tienen un ancho del 12%. Los distribuimos uniformemente a través del eje principal dando justify-content: space-around a la lista principal.
  • Deben estar situados en la parte inferior de su contenedor y, por lo tanto, establecemos align-items: flex-end a la lista principal.
  • Su altura inicial es 0. Tan pronto como la sección se hace visible, su altura se anima y recibe un valor igual al valor de su atributo data-height. Solo ten en cuenta que debemos reescribir los valores de altura deseados en nuestro CSS porque establecer height: attr(data-height) no funciona :(

Aquí están los estilos relacionados:

1
:root {
2
  ...
3
  --transition-delay: 0.85s;
4
  --transition-delay-step: 0.3s;
5
}
6
7
.chart-skills li {
8
  width: 12%;
9
  height: 0;
10
  border-top-left-radius: 10px;
11
  border-top-right-radius: 10px;
12
  transition: height 0.65s cubic-bezier(0.51, 0.91, 0.24, 1.16);
13
}
14
15
.window-opened .chart-skills li:nth-child(1) {
16
  height: 80%;
17
  transition-delay: var(--transition-delay);
18
}
19
20
.window-opened .chart-skills li:nth-child(2) {
21
  height: 60%;
22
  transition-delay: calc(
23
    var(--transition-delay) + var(--transition-delay-step)
24
  );
25
}
26
27
.window-opened .chart-skills li:nth-child(3) {
28
  height: 68%;
29
  transition-delay: calc(
30
    var(--transition-delay) + var(--transition-delay-step) * 2
31
  );
32
}
33
34
.window-opened .chart-skills li:nth-child(4) {
35
  height: 52%;
36
  transition-delay: calc(
37
    var(--transition-delay) + var(--transition-delay-step) * 3
38
  );
39
}
40
41
.window-opened .chart-skills li:nth-child(5) {
42
  height: 42%;
43
  transition-delay: calc(
44
    var(--transition-delay) + var(--transition-delay-step) * 4
45
  );
46
}

Como puedes ver en el código anterior, utilizamos las variables de CSS transition-delay y transition-delay-step junto con la función calc() CSS para controlar la velocidad de los efectos de transición. Microsoft Edge no soporta esas operaciones matemáticas, así que si necesitas admitirlo, pasa algunos valores estáticos como este:

1
.window-opened .chart-skills li:nth-child(2) {
2
  transition-delay: 1.15s;
3
}
4
5
.window-opened .chart-skills li:nth-child(3) {
6
  transition-delay: 1.45s;
7
}

Para generar la cantidad de conocimiento estipulada para una cierta tecnología, usaremos el pseudo-elemento ::before.

Using sudo element to output the amount of knowledge

Este valor se extrae del atributo data-height que se asigna a los elementos de la segunda lista.

Aquí están los estilos que realizan este trabajo:

1
.chart-skills li::before { 
2
  content: attr(data-height);
3
  position: absolute;
4
  top: 10px;
5
  left: 0;
6
  width: 100%;
7
  font-size: 0.85rem;
8
  color: var(--white);
9
}

Por último, añadimos algunos estilos al elemento span que está situado dentro de cada uno de los elementos de la lista. Este elemento se comporta como una etiqueta y almacena los nombres de la tecnología.

The technology names

Los estilos correspondientes:

1
.chart-skills span {
2
  bottom: 0;
3
  left: 0;
4
  transform: translateY(40px) rotate(45deg);
5
}

5. Volviéndola responsiva

¡Ya casi hemos terminado! Como último punto, asegurémonos de que la página tenga una apariencia sólida en todas las pantallas. Aplicaremos dos reglas específicamente para las pantallas estrechas:

1
@media screen and (max-width: 600px) {
2
  html {
3
    font-size: 12px;
4
  }
5
  
6
  .chart-levels li {
7
    padding: 15px 10px 15px 0;
8
  }
9
}

Una nota importante aquí es que en nuestros estilos hemos utilizado rem para ajustar el tamaño de las fuente. Este enfoque es realmente útil porque los tamaños de las fuentes no son absolutos y sus valores dependen del valor del elemento raíz. Por lo tanto, si disminuimos el tamaño de la fuente del elemento raíz como en el código anterior, los tamaños de la fuente relacionados con rem disminuirán de forma dinámica. ¡Buen trabajo amigos!

El estado final de nuestro proyecto:

6. Compatibilidad con navegadores

La demostración funciona bien en todos los navegadores y dispositivos recientes.

Como ya se comentó anteriormente, Microsoft Edge aún no soporta operaciones matemáticas con propiedades personalizadas dentro de la función calc(). Para superar este problema, deberás usar valores codificados en su lugar.


Conclusión

En este tutorial, mejoramos nuestras habilidades con flexbox creando una atractiva página estática para portafolios. Incluso nos desafiamos a nosotros mismos, pues hemos aprendido a crear un gráfico de columnas responsivo sin usar ninguna biblioteca externa de JavaScript, SVG, o el elemento canvas. ¡Solamente con CSS!

Espero que hayas disfrutado este tutorial tanto como yo disfruté escribiéndolo, y que esta demostración te inspire para desarrollar el sitio para tu portafolio. Me encantaría ver tu trabajo, ¡asegúrate de compartirlo con nosotros!

Lecturas adicionales

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Web Design tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.