Image Gallery
The photo gallery is a module used for managing images on a website. It primarily serves for browsing and enlarging pictures related to a common category. The module can be used to enlarge product photos, to present a portfolio, or as a slideshow. The following assumptions accompanied the creation of my application:
- The gallery should use easy-to-edit and efficient CSS3 animations
- XMLHttpRequest should be responsible for loading images
- The photo gallery should be independent of external applications
- The module should work in album mode and must retrieve the list of images found on other pages
- It's desirable for the application to have an interactive thumbnail list
- The application should automatically change images
- The gallery should allow for the maximum enlargement of the image
According to the above assumptions, I created an application that allows for free browsing of images, creating custom animations, easy and quick customization of appearance, and the ability to create albums on the website. All options and required instructions for installation have been presented in the pages of this post (menu on the left side of the screen or in the lower right corner). I encourage you to read it.
<nav class="gallery">
<div class="gallery-row">
<a href="uploads/images/blog/galeria/galeria-01.jpg" class="gallery-thumbnail gallery-item"><img src="uploads/images/blog/galeria/galeria-m-01.jpg" alt="Miniatura zdjęcia"></a>
<a href="uploads/images/blog/galeria/galeria-02.jpg" class="gallery-thumbnail gallery-item"><img src="uploads/images/blog/galeria/galeria-m-02.jpg" alt="Miniatura zdjęcia"></a>
<a href="uploads/images/blog/galeria/galeria-03.jpg" class="gallery-thumbnail gallery-item"><img src="uploads/images/blog/galeria/galeria-m-03.jpg" alt="Miniatura zdjęcia"></a>
<a href="uploads/images/blog/galeria/galeria-04.jpg" class="gallery-thumbnail gallery-item"><img src="uploads/images/blog/galeria/galeria-m-04.jpg" alt="Miniatura zdjęcia"></a>
<a href="uploads/images/blog/galeria/galeria-05.jpg" class="gallery-thumbnail gallery-item"><img src="uploads/images/blog/galeria/galeria-m-05.jpg" alt="Miniatura zdjęcia"></a>
</div>
<div class="gallery-row">
<a href="uploads/images/blog/galeria/galeria-06.jpg" class="gallery-thumbnail gallery-item"><img src="uploads/images/blog/galeria/galeria-m-06.jpg" alt="Miniatura zdjęcia"></a>
<a href="uploads/images/blog/galeria/galeria-07.jpg" class="gallery-thumbnail gallery-item"><img src="uploads/images/blog/galeria/galeria-m-07.jpg" alt="Miniatura zdjęcia"></a>
<a href="uploads/images/blog/galeria/galeria-08.jpg" class="gallery-thumbnail gallery-item"><img src="uploads/images/blog/galeria/galeria-m-08.jpg" alt="Miniatura zdjęcia"></a>
<a href="uploads/images/blog/galeria/galeria-09.jpg" class="gallery-thumbnail gallery-item"><img src="uploads/images/blog/galeria/galeria-m-09.jpg" alt="Miniatura zdjęcia"></a>
<a href="uploads/images/blog/galeria/galeria-10.jpg" class="gallery-thumbnail gallery-item"><img src="uploads/images/blog/galeria/galeria-m-10.jpg" alt="Miniatura zdjęcia"></a>
</div>
</nav>
.compsoul-gallery-div, .compsoul-gallery-small, .compsoul-gallery-small,
.compsoul-gallery-big, .compsoul-gallery-hash, .compsoul-gallery-hash-test,
.compsoul-gallery-comment, .compsoul-gallery-comment-inside, .compsoul-gallery-comment-mix, .compsoul-gallery {
display: inline-block;
position: relative;
}
.compsoul-gallery-div:after, .compsoul-gallery-small:after, .compsoul-gallery-small:after,
.compsoul-gallery-big:after, .compsoul-gallery-hash:after, .compsoul-gallery-hash-test:after,
.compsoul-gallery-comment:after, .compsoul-gallery-comment-inside:after, .compsoul-gallery-comment-mix:after, .compsoul-gallery:after {
bottom: 0;
content: "";
left: 0;
position: absolute;
right: 0;
top: 0;
}
.compsoul-gallery {
display: inline-block;
max-width: 80%;
}
.compsoul-gallery-container {
background: rgba(25, 25, 25, 0.96);
bottom: 0;
font-size: 8px;
left: 0;
position: fixed;
right: 0;
top: 0;
will-change: auto;
z-index: 10;
}
.compsoul-gallery-container .compsoul-hidden {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
position: absolute;
padding: 0;
width: 1px;
}
.compsoul-gallery-container.compsoul-active {
animation: gallery-container 0.2s linear;
will-change: opacity;
}
.compsoul-gallery-container.compsoul-inactive {
animation: gallery-container-close 0.2s linear forwards;
will-change: opacity;
}
@keyframes gallery-container {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes gallery-container-close {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
.compsoul-gallery-container button {
background: none;
border: none;
cursor: pointer;
font-size: inherit;
line-height: 0;
margin: 0;
padding: 0;
}
.compsoul-gallery-content {
bottom: 0;
position: absolute;
left: 0;
right: 0;
top: 0;
z-index: 0;
}
.thumbnails-active .compsoul-gallery-content {
bottom: 120px;
}
.thumbnails-inactive .compsoul-gallery-content {
bottom: 0;
}
.compsoul-gallery-content .compsoul-gallery-item {
height: 80vh;
height: calc(100vh - 172px);
left: 50%;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
user-select: none;
visibility: hidden;
width: 80vw;
width: calc(100vw - 204px);
will-change: auto;
z-index: 0;
}
.compsoul-gallery-item.compsoul-active, .compsoul-gallery-item.compsoul-prev, .compsoul-gallery-item.compsoul-next {
opacity: 1;
transform: translate(-150vw, -50%);
transition: opacity 0.3s ease-out, transform 0.3s ease-out;
visibility: visible;
will-change: opacity, transform;
z-index: 1;
}
.compsoul-gallery-item.compsoul-fade {
opacity: 0;
transition: opacity 0.2s ease-out;
visibility: visible;
will-change: opacity;
}
.compsoul-direction-prev .compsoul-gallery-item.compsoul-prev,
.compsoul-direction-next .compsoul-gallery-item.compsoul-next {
transition: unset;
will-change: auto;
}
.compsoul-resize .compsoul-gallery-item.compsoul-prev {
animation: compsoul-resize-prev 0.1s linear forwards;
}
@keyframes compsoul-resize-prev {
from {
transform: translate(-150vw, -50%);
}
to {
transform: translate(-150vw, -50%);
}
}
.compsoul-resize .compsoul-gallery-item.compsoul-next {
animation: compsoul-resize-next 0.1s linear forwards;
}
@keyframes compsoul-resize-next {
from {
transform: translate(50vw, -50%);
}
to {
transform: translate(50vw, -50%);
}
}
.compsoul-gallery-item.compsoul-next {
transform: translate(50vw, -50%);
}
.compsoul-gallery-item.compsoul-active {
transform: translate(-50%, -50%);
}
.compsoul-disorderly .compsoul-gallery-item,
.compsoul-disorderly .compsoul-gallery-item.compsoul-prev,
.compsoul-disorderly .compsoul-gallery-item.compsoul-next {
opacity: 0;
transition: unset;
visibility: hidden;
will-change: auto;
z-index: 2;
}
.compsoul-disorderly .compsoul-gallery-item.compsoul-past {
animation: disorderly-past 0.2s linear;
will-change: opacity, transform, visibility;
z-index: 3;
}
@keyframes disorderly-past {
0% {
opacity: 1;
transform: translate(-50%, -50%);
visibility: visible;
}
99% {
opacity: 0;
transform: translate(-50%, -50%);
visibility: visible;
}
100% {
opacity: 0;
transform: translate(-50%, -50%);
visibility: hidden;
}
}
.compsoul-disorderly .compsoul-gallery-item.compsoul-active {
animation: disorderly-active 0.2s linear;
opacity: 1;
visibility: visible;
will-change: opacity, transform, visibility;
z-index: 4;
}
@keyframes disorderly-active {
0% {
opacity: 0;
transform: translate(-50%, -50%);
visibility: hidden;
}
1% {
opacity: 0;
transform: translate(-50%, -50%);
visibility: visible;
}
100% {
opacity: 1;
transform: translate(-50%, -50%);
visibility: visible;
}
}
.compsoul-gallery-item .compsoul-gallery-image {
display: inline-block;
left: 50%;
opacity: 0.001;
overflow: hidden;
position: relative;
top: 50%;
transform: translate(-50%, -50%);
transform-origin: top left;
will-change: auto;
width: auto;
z-index: 1;
}
.compsoul-gallery-item.compsoul-active .compsoul-gallery-image {
transition: opacity 0.2s 0.2s linear, transform 0.2s linear;
will-change: opacity;
}
.compsoul-gallery-item .compsoul-gallery-image:before {
bottom: 0;
content: "";
left: 0;
position: absolute;
right: 0;
top: 0;
}
.thumbnails-show .compsoul-gallery-image {
transform: scale(0.8) translate(-50%, -50%);
}
.thumbnails-show .compsoul-gallery-item.compsoul-active .compsoul-gallery-image {
will-change: transform;
}
.compsoul-gallery-item.compsoul-loaded .compsoul-gallery-image {
opacity: 1;
}
.compsoul-gallery-item .compsoul-gallery-image img {
display: block;
max-height: 80vh;
max-height: calc(100vh - 172px);
max-width: 80vw;
max-width: calc(100vw - 204px);
}
.compsoul-gallery-item .compsoul-gallery-comment {
background: rgba(0, 0, 0, 0.6);
bottom: 0;
color: #f2f2f2;
font-family: Calibri, Candara, Segoe, Segoe UI, Optima, Arial, sans-serif;
font-size: 2em;
left: 0;
padding: 2em;
position: absolute;
right: 0;
transform: translate(0, 100%);
transition: transform 0.2s 0.4s linear;
z-index: 1;
}
.compsoul-disorderly .compsoul-gallery-item .compsoul-gallery-comment {
transform: translate(0, 0);
transition: unset;
}
.compsoul-gallery-item.compsoul-active.compsoul-loaded .compsoul-gallery-comment {
transform: translate(0, 0);
}
.compsoul-gallery-item .compsoul-gallery-comment.compsoul-inactive {
display: none;
}
.compsoul-loader {
left: 50%;
opacity: 0;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
z-index: 0;
}
.compsoul-loader:before, .compsoul-loader:after {
animation: compsoul-loading 1s linear infinite;
animation-play-state: paused;
border: 0.5em solid #f2f2f2;
border-radius: 100%;
content: "";
display: block;
filter: blur(1px);
height: 8em;
left: 50%;
opacity: 0;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
width: 8em;
}
.compsoul-gallery-item.compsoul-active .compsoul-loader,
.compsoul-gallery-item.compsoul-prev .compsoul-loader,
.compsoul-gallery-item.compsoul-next .compsoul-loader {
transition: opacity 0.2s linear;
}
.compsoul-gallery-item.compsoul-active .compsoul-loader {
opacity: 1;
}
.compsoul-gallery-item.compsoul-loaded .compsoul-loader {
opacity: 0;
}
.compsoul-gallery-item.compsoul-active.compsoul-loading .compsoul-loader:before,
.compsoul-gallery-item.compsoul-active.compsoul-loading .compsoul-loader:after {
animation-play-state: running;
}
.compsoul-loader:after {
animation-delay: 0.5s;
}
@keyframes compsoul-loading {
0% {
opacity: 0;
transform: translate(-50%, -50%) scale(0);
}
50% {
opacity: 1;
transform: translate(-50%, -50%) scale(0.5);
}
100% {
opacity: 0;
transform: translate(-50%, -50%) scale(1);
}
}
.compsoul-gallery-full-screen {
background: #000;
bottom: 0;
font-size: 0;
position: absolute;
left: 0;
opacity: 0;
overflow: auto;
right: 0;
top: 0;
transition: opacity 0.2s linear;
z-index: -1;
}
.compsoul-gallery-full-screen.compsoul-active {
z-index: 1;
}
.compsoul-zoom .compsoul-gallery-full-screen {
opacity: 1;
}
.compsoul-zoom-out .compsoul-gallery-full-screen {
opacity: 0;
transition-delay: 0.2s;
}
.compsoul-gallery-full-screen img {
display: block;
margin: 0 auto;
opacity: 0;
transition: opacity 0.2s 0.2s linear;
}
.compsoul-zoom .compsoul-gallery-full-screen img {
opacity: 1;
}
.compsoul-zoom-out .compsoul-gallery-full-screen img {
opacity: 0;
transition-delay: unset;
}
.compsoul-logo, .compsoul-gallery-close, .compsoul-gallery-next, .compsoul-gallery-prev, .thumbnails-toggle, .compsoul-gallery-progress, .compsoul-gallery-zoom {
cursor: pointer;
height: 7em;
outline: 1px solid rgba(242, 242, 242, 0);
overflow: hidden;
position: absolute;
right: 4em;
top: 2em;
transform: translate(0);
transition: outline 0.2s linear;
width: 7em;
}
.compsoul-logo {
box-sizing: border-box;
left: 4em;
right: auto;
transition: unset;
width: 8em;
}
.compsoul-logo svg {
fill: #f2f2f2;
top: 50%;
position: relative;
transform: translate(0, -50%);
transition: fill 0.2s linear;
}
.compsoul-logo:focus-within {
outline: none;
}
.compsoul-logo:hover svg, .compsoul-logo:focus-within svg {
fill: #e7a14f;
}
.compsoul-logo:focus-within, .compsoul-gallery-close:focus-within, .compsoul-gallery-next:focus-within, .compsoul-gallery-prev:focus-within, .thumbnails-toggle:focus-within, .compsoul-gallery-progress:focus-within, .compsoul-gallery-zoom:focus-within {
outline-color: rgba(242, 242, 242, 0.8);
}
.compsoul-gallery-close:before, .compsoul-gallery-next:before, .compsoul-gallery-prev:before, .thumbnails-toggle:before, .compsoul-gallery-progress:before, .compsoul-gallery-zoom:before, .compsoul-gallery-close:after, .compsoul-gallery-next:after, .compsoul-gallery-prev:after, .thumbnails-toggle:after, .compsoul-gallery-progress:after, .compsoul-gallery-zoom:after {
background: #111;
bottom: 0;
content: "";
position: absolute;
left: 0;
right: 0;
top: 0;
z-index: -2;
}
.compsoul-gallery-close:after, .compsoul-gallery-next:after, .compsoul-gallery-prev:after, .thumbnails-toggle:after, .compsoul-gallery-progress:after, .compsoul-gallery-zoom:after {
background: none;
z-index: 1;
}
.compsoul-gallery-close button, .compsoul-gallery-next button, .compsoul-gallery-prev button, .thumbnails-toggle button, .compsoul-gallery-progress button, .compsoul-gallery-zoom button {
outline: 0;
position: relative;
z-index: -1;
}
.compsoul-gallery-close button:before, .compsoul-gallery-close button:after, .compsoul-gallery-next button:before, .compsoul-gallery-prev button:before {
border-top: 0.25em solid #f2f2f2;
border-right: 0.25em solid #f2f2f2;
box-sizing: content-box;
content: "";
cursor: pointer;
display: inline-block;
height: 1em;
padding: 0 0 0.25em 0.25em;
width: 1em;
}
.compsoul-gallery-close {
z-index: 2;
}
.compsoul-gallery-close button {
cursor: pointer;
height: 6em;
left: 50%;
position: absolute;
top: 50%;
transform: translate(-50%, -50%) rotate(45deg);
width: 6em;
}
.compsoul-gallery-close button:before, .compsoul-gallery-close button:after {
bottom: 1.625em;
left: 1.625em;
position: absolute;
transform: rotate(0deg);
}
.compsoul-gallery-close button:before {
border: none;
border-bottom: 0.25em solid #f2f2f2;
border-left: 0.25em solid #f2f2f2;
left: auto;
padding: 0.25em 0.25em 0 0;
right: 1.625em;
top: 1.625em;
}
.compsoul-gallery-close button:after {
border-top: 0.25em solid #f2f2f2;
border-right: 0.25em solid #f2f2f2;
padding: 0 0 0.25em 0.25em;
}
.compsoul-gallery-zoom {
right: 28em;
}
.compsoul-gallery-zoom button {
cursor: pointer;
height: 100%;
position: relative;
width: 100%;
}
.compsoul-gallery-zoom button:before {
border: 0.25em solid #f2f2f2;
border-radius: 100%;
content: "";
height: 1.25em;
left: 50%;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
width: 1.25em;
}
.compsoul-gallery-zoom button:after {
background: #f2f2f2;
border-radius: 0 0 0.25em 0.25em;
content: "";
height: 1em;
left: 50%;
margin: 1em 0 0 -1.5em;
position: absolute;
top: 50%;
transform: rotate(45deg) translate(-50%, -50%);
width: 0.25em;
}
.compsoul-gallery-progress {
right: 20em;
}
.compsoul-gallery-progress button {
cursor: pointer;
height: 100%;
position: relative;
width: 100%;
}
.compsoul-gallery-progress button:before {
border-bottom: 1em solid transparent;
border-left: 1.2em solid #f2f2f2;
border-top: 1em solid transparent;
border-radius: 0.2em;
content: "";
height: 0;
left: 50%;
opacity: 1;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
transition: opacity 0.2s 0.2s linear;
width: 0;
}
.compsoul-gallery-progress.compsoul-active button:before {
opacity: 0;
transition-delay: unset;
}
.compsoul-gallery-progress button:after {
animation: gallery-progress 6s linear forwards;
animation-play-state: paused;
color: #f2f2f2;
content: "10";
font-size: 1.6em;
left: 50%;
opacity: 0;
position: absolute;
top: 50%;
transition: opacity 0.2s linear;
transform: translate(-50%, -50%);
}
.compsoul-gallery-progress.compsoul-active button:after {
opacity: 1;
transition-delay: 0.2s;
}
.compsoul-gallery-progress.compsoul-play button:after {
animation-delay: 0.4s;
animation-play-state: running;
}
.compsoul-gallery-progress.compsoul-unset button:after {
animation: unset;
}
@keyframes gallery-progress {
0% {
content: "10";
}
9% {
content: "9";
}
18% {
content: "8";
}
27% {
content: "7";
}
36% {
content: "6";
}
45% {
content: "5";
}
54% {
content: "4";
}
63% {
content: "3";
}
72% {
content: "2";
}
81% {
content: "1";
}
90% {
content: "0";
}
100% {
content: "0";
}
}
.compsoul-gallery-next, .compsoul-gallery-prev {
opacity: 0;
right: 4em;
top: 50%;
transform: translate(0, -50%);
transition: opacity 0.2s linear, outline 0.2s linear;
}
.compsoul-gallery-next.compsoul-active, .compsoul-gallery-prev.compsoul-active {
opacity: 1;
}
.compsoul-gallery-prev {
left: 4em;
}
.compsoul-gallery-next button, .compsoul-gallery-prev button {
left: 50%;
position: absolute;
top: 50%;
transform: translate(-1em, -50%);
}
.compsoul-gallery-prev button {
transform: translate(-0.5em, -50%);
}
.compsoul-gallery-next button:before, .compsoul-gallery-prev button:before {
transform: rotate(-135deg);
}
.compsoul-gallery-next button:before {
transform: rotate(45deg);
}
.thumbnails-toggle {
right: 12em;
}
.thumbnails-toggle button {
cursor: pointer;
height: 100%;
position: relative;
width: 100%;
}
.thumbnails-toggle button:before {
background-color: transparent;
background-image: linear-gradient(90deg, #f2f2f2 0.5em, transparent 0.25em),
linear-gradient(90deg, #f2f2f2 0.5em, transparent 0.25em),
linear-gradient(90deg, #f2f2f2 0.5em, transparent 0.25em);
background-position: 0 0, 0 0.75em, 0 1.5em;
background-repeat: repeat-x;
background-size: 0.75em 0.5em, 0.75em 0.5em, 0.75em 0.5em;
content: "";
cursor: pointer;
height: 2em;
left: 50%;
opacity: 0.6;
position: absolute;
top: 50%;
transition: opacity 0.4s linear;
transform: translate(-50%, -50%);
width: 2em;
}
.thumbnails-toggle:active button:before, .thumbnails-toggle button:active:before {
background-image: linear-gradient(90deg, #f2f2f2 0.5em, transparent 0.125em),
linear-gradient(90deg, #f2f2f2 0.5em, transparent 0.125em),
linear-gradient(90deg, #f2f2f2 0.5em, transparent 0.125em);
background-position: 0 0, 0 0.625em, 0 1.25em;
background-size: 0.625em 0.5em, 0.625em 0.5em, 0.625em 0.5em;
height: 1.75em;
width: 1.75em;
}
.thumbnails-show .thumbnails-toggle button:before {
opacity: 1;
}
.thumbnails-container {
background: #111;
bottom: 0;
font-size: 0;
height: 72px;
left: 0;
letter-spacing: 0;
position: fixed;
right: 0;
transition: transform 0.2s linear;
transform: translateY(100%);
}
.thumbnails-show .thumbnails-container {
transform: translateY(0);
}
.thumbnails-content {
bottom: 0;
left: 0;
position: absolute;
top: 0;
white-space: nowrap;
}
.thumbnails-show .thumbnails-content {
transition: transform 0.2s linear;
}
.thumbnails-content.compsoul-drag {
transition: unset;
}
.thumbnails-content.compsoul-drag:before {
bottom: 0;
content: "";
left: 0;
position: absolute;
right: 0;
top: 0;
z-index: 2;
}
.thumbnails-content .thumbnails-image {
background: none;
border: none;
cursor: pointer;
display: inline-block;
font-size: 0;
height: 100%;
position: relative;
user-select: none;
}
.thumbnails-content .thumbnails-image:before, .thumbnails-content .thumbnails-image:after {
bottom: 0;
content: "";
left: 0;
opacity: 0;
outline: 1px solid #f2f2f2;
outline-offset: -1px;
position: absolute;
right: 0;
top: 0;
transition: opacity 0.2s linear;
z-index: 1;
}
.thumbnails-content .thumbnails-image:after {
outline-color: #e7a14f;
}
.thumbnails-content .thumbnails-image button:focus {
outline: none;
}
.thumbnails-content .thumbnails-image:focus-within:before {
opacity: 1;
}
.thumbnails-content .thumbnails-image.compsoul-active:after {
opacity: 1;
}
.thumbnails-content .thumbnails-image img {
display: block;
max-height: 72px;
}
.gallery {
display: flex;
flex-flow: row wrap;
gap: 10px;
}
.gallery-row {
display: flex;
flex: 1 100%;
flex-flow: row nowrap;
gap: 10px;
}
.gallery-thumbnail * {
pointer-events: none;
}
.gallery-thumbnail img {
height: 100%;
object-fit: cover;
width: 100%;
}
@media (max-width: 1000px) {
.compsoul-gallery-container {
font-size: 5.4px;
}
.compsoul-gallery-content .compsoul-gallery-item {
height: 100vh;
height: calc(100vh - 16px);
width: 100vw;
width: calc(100vw - 16px);
}
.thumbnails-show .compsoul-gallery-image {
transform: scale(0.68) translate(-50%, -50%);
}
.compsoul-gallery-item .compsoul-gallery-image img {
max-height: 100vh;
max-height: calc(100vh - 16px);
max-width: 100vw;
max-width: calc(100vw - 16px);
}
}
@media (max-width: 380px) {
.compsoul-gallery-content .compsoul-gallery-item {
height: 100vh;
width: 100vw;
}
.thumbnails-show .compsoul-gallery-image {
transform: scale(0.75) translate(-50%, -50%);
}
.compsoul-gallery-item .compsoul-gallery-image img {
max-height: 100vh;
max-width: 100vw;
}
}
<script src="https://compsoul.dev/uploads/js/compsoul.js"></script><script src="https://compsoul.dev/uploads/js/gallery.js"></script><script>
new Gallery(".gallery-item").init();
</script>
Comments
mc1f90,Article,Magal
Magal
Magal
Daniel