Co to jest ten baner, to nic innego zdjęcie znajdujące się w div, które przesuwa się z góry na dół i ponownie na górę i tak w nieskończoność.
Oczywiście nic nas nie ogranicza można dodać np. jakiś tekst 🙂
Najpierw prosty html, na potrzeby tego przykładu kontener będzie centrowany w pionie i poziomie na całej stronie.
<div class="container">
<div class="image-bgr">
<img src="http://www.grzegorztomicki.pl/images/lwow/992/IMG_0014.jpg" alt="" class="image-responsive">
</div>
</div>
Teraz odpowiedni styl do wyświetlenia tego zdjęcia centralnie.
* {
box-sizing: border-box;
padding: 0;
margin: 0;
}
html {
height: 100%;
}
body {
display: flex;
height: 100%;
width: 100%;
justify-content: center;
align-items: center;
}
.container {
width: 100%;
padding: 0 20px;
}
.image-bgr {
position: relative;
width: 100%;
max-width: 900px;
height: auto;
min-height: 220px;
overflow: hidden;
margin: auto;
}
.image-bgr img {
width: 100%;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
Najważniejsze klasy to w naszym przykładzie ".image-bgr" oraz ".image-bgr img"
Pierwsza klasa tworzy box o wymiarach max 900px i min wysokości 220px.
Do tego posiada właściwość overflow hidden aby ukryć wszystko co wystaję poza obwód boxa.
Druga klasa, a dokładnie ta sam tylko że z elementem img dotyczy zdjęcia. Zdjęcie to ustawiamy jako position absolute. Centrujemy je tak aby było maksymalnie ustawione na 100% szerokości boxa. Do tego zdjęcie jest centrowane w pionie.
Teraz cześć najważniejsza - javascript
function animBanner(config) {
// sięgamy po box
const boxScroll = document.querySelector('.image-bgr');
// sięgamy po zdjęcie
const image = document.querySelector('.image-responsive');
// pobieramy rozmiar zdjęcia a dokładnie wysokość
const imageHeight = image.clientHeight;
// pobieramy wysokość boxa
const boxHeight = boxScroll.clientHeight;
// pobieramy szerokość okna
const documentWidth = document.body.clientWidth;
// ustalamy o ile należy przesunąć zdjęcie względem boxa top/bottom
const margin = (imageHeight - boxHeight) / 2;
// za każdym razem usuwamy atrybut style z elementu img
image.removeAttribute('style');
// ustawiamy nowy atrybut style
image.setAttribute('style', `animation: ${config}`);
// wywołujemy funkcję która usuwa style z head
animClear(image);
// tutaj sprawdzamy czy szerokość okna jest większa czy równa 600px
// jeżeli tak wtedy wywołujemy funkcję która tworzy styl z keyframes
if (documentWidth >= 600) {
animStyle(margin);
}
}
// funkcja czyszcząca style
function animClear() {
const imageStyle = document.querySelector('#animBanner');
if (imageStyle) {
imageStyle.parentNode.removeChild(imageStyle);
}
}
// funkcja tworzące style, które następnie są dodawane do head strony
function animStyle(margin) {
const keyFrames = animKeyframes(margin);
const style = document.createElement('style');
style.type = 'text/css';
style.id = 'animBanner'
style.appendChild(document.createTextNode(keyFrames));
document.head.appendChild(style)
}
// funkcja tworząca animację
function animKeyframes(margin) {
const percent = `
0% {
-webkit-transform: translate3d(0, -${margin}px, 0);
transform: translate3d(0, -${margin}px, 0);
}
50% {
-webkit-transform: translate3d(0, ${margin}px, 0);
transform: translate3d(0, ${margin}px, 0);
}
100% {
-webkit-transform: translate3d(0, -${margin}px, 0);
transform: translate3d(0, -${margin}px, 0);
}
`;
return `@-webkit-keyframes animBanner { ${percent} } @keyframes anim { ${percent} }`;
}
// Stała dodawana do elementu image w boxie
// Za pomocą tego stylu uruchamiamy animację, która trwa 25s
// ease-out sposób animacji, a ostatni prametr infinite to określa
// że animacja będzie odbywać się w nieskończoność
const config = 'animBanner 25s ease-out infinite';
// po załadowaniu całej strony uruchamiamy funkcję animBanner
// do tej funkcji jest przekazywany config
window.addEventListener('DOMContentLoaded', animBanner(config));
// Ta część jest najważniejsza, w związku z tym że strony są responsive
// Wprowadzona tutaj została opcja zmieniania wielkości boxa jak i zdjęcia
// ale żeby wszystkie elementy się skalowały odpowiednio należy za każdym razem
// po zmniejszeniu okna wywołać na nowo funkcję która od nowa nada nowe marginesy itd.
// Tutaj użyłem małego triku które likwiduje problem z resizem i każdorazowym
// wywołaniem funkcji. Polega on na tym że dopiero po zmniejszeniu i po 260ms
// jest wywoływana funkcja, jest to podyktowane optymalizacją.
let resizeTimer;
window.addEventListener('resize', () => {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(() => {
animBanner(config);
}, 250);
});
Co zyskujemy że animacja odbywa się stylach, jest to płynne przewijanie z szybkością przekraczająca 60fps. Czyli animacja bardzo płynna.
Poniżej cały działający przykład.
See the Pen
slow scrolling of the photo by Greg (@Tomik23)
on CodePen.