En esta ocasión he construido una landing con la idea de practicar con display grid
y position sticky
Al final he he ido metiendo más cositas, como menú lateral tipo navigation drawer
, customización de Scroll, animación de scroll en los enlaces internos y animación de texto "spliteado".
Para la animación de menú me he basado en algo muy chulo que está publicado en Codrops y para la customización de Scroll este Codepen
Comentaré brevemente:
- CSS grid y sticky
- Animación de textos
CSS grid y sticky
He creado cuatro secciones diferentes en las que iba colocando cajas con texto y cajas para imágenes.
La creación de filas/columnas la hice mediante grid-template-columns
y grid-template-rows
y cada caja dentro tomaba los tamaños en función de la cuadrícula en cada caso
El posicionamiento sticky
lo he añadido mediante dos clases txt--sticky-top
y txt--sticky-bottom
que serán válidas según el tamaño de pantalla mínimo que me interese. La primera tiene el valor top: 0
y la segunda bottom: 0
para que se alineen dentro en la cara que interese dentro de su contenedor al hacer scroll. Existe un caso, que por defecto la caja de texto está centrado verticalmente respecto de su elemento padre, para este caso he usado ambas clases conjuntamente
El CSS del primer ejemplo sería:
.container-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-template-rows: repeat(2, minmax(300px, auto));
&--schema-1 {
.div1 { grid-area: 1 / 1 / 3 / 2; }
.div2 { grid-area: 1 / 2 / 3 / 3; }
.div3 { grid-area: 1 / 3 / 2 / 4; }
.div4 { grid-area: 1 / 4 / 2 / 5; }
.div5 { grid-area: 2 / 3 / 3 / 4; }
.div6 { grid-area: 2 / 4 / 3 / 5; }
}
}
.txt {
&--sticky-top {
position: sticky;
top: 0;
}
&--sticky-bottom {
position: sticky;
bottom: 0;
}
//Resto de código
}
Para la parte de HTML he añadido las imágenes como background
El HTML del primer ejemplo
<section class="container-grid container-grid--schema-1">
<article class="div1 txt txt--right">
<h4 class="title-box">Título de la caja principal</h4>
<p class="txt-box">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ea explicabo laboriosam nulla inventore quasi accusamus, obcaecati impedit natus nisi est, voluptatibus aliquid porro exercitationem maxime modi, sequi distinctio at? Totam!</p>
</article>
<div class="div2 bg" style="background-image: url(img/underwater.jpg);"></div>
<div class="div3 bg" style="background-image: url(img/marigold.jpg);"></div>
<article class="div4 txt txt--scnd txt--sticky-top">
<h4 class="title-box">Título</h4>
<h5 class="txt-box">Subtítulo, breve descripción con Heading 3</h5>
</article>
<article class="div5 txt txt--scnd txt--sticky-bottom">
<h4 class="title-box">Titulo</h4>
<h5 class="txt-box">Subtítulo, breve descripción con Heading 3</h5>
</article>
<div class="div6 bg" style="background-image: url(img/kingfisher.jpg);"></div>
</section>
Animación de textos
La animación de entrada de textos en el "Slider" lo ha realizado:
- Aplicando con JS split de cada letra
- Animación de entradas y salidas de textos con CSS keyframes
- Cada una de las letras tendrá un "delay", tanto en entrada como en salida
Las funciones JS para realizar el Split y añadir clases, atributos y estilos son las siguientes:
const elFactory = (type, attributes, ...children) => {
const el = document.createElement(type)
for (key in attributes) {
el.setAttribute(key, attributes[key])
}
children.forEach(child => {
if (typeof child === 'string') el.appendChild(document.createTextNode(child))
else el.appendChild(child)
})
return el
}
const sliptWords = words => {
const fragment = new DocumentFragment();
let globalIndex = 0;
words.split(' ').forEach((word, iWord) => {
const fragmentLetter = new DocumentFragment();
word.split('').forEach((letter, iLetter) => {
globalIndex++;
const el = elFactory(
'span',
{
'data-letter': `${letter}`,
class: `letter`,
style: `--letter-index:${iLetter+1}; --global-index: ${globalIndex};`
},
`${letter}`
)
fragmentLetter.appendChild(el);
})
const space = elFactory(
'span',
{
'data-space': true,
class: `space`
},
` `
)
fragmentLetter.appendChild(space);
const el = elFactory(
'span',
{
'data-word': `${word}`,
class: `word`,
style: `--word-index:${iWord+1}`
},
fragmentLetter
)
fragment.appendChild(el);
})
return fragment;
}
La animación se producirá a aquellos elementos HTML que tengan el atributo [data-split-word]
let splits = document.querySelectorAll('[data-split-word]');
splits.forEach(split => {
let splitTextContent = split.textContent;
split.innerHTML = '';
split.appendChild(sliptWords(splitTextContent))
})
Esta landing tiene más cosas como por ejemplo:
- Animación de scroll usando
scrollIntoView
- Menú lateral con animación de SVG
- Uso de
mix-blend-mode
bajo el slider - Customización de ScrollBar
Puede verse todo el código en mi Git