A Grizzly Comes Into the Viewport
He looks at me...
He seems to turn...
Yes! Go that way!
Uh Oh!
He turns towards me!
I jump on a rock and don't move
He growls! Look at the spikes on his hair!
Please continue going Bear!
Bye Bye!

In this article, I will show you how to implement sliders and carousels with stunning transition effects using Swiper. We will also discuss carousels' benefits and drawbacks and when to use them. We also include an example Swiper application allowing you to build your own Swiper carousel using Uppy and ColdFusion. 


What is Swiper?

Swiper is an open-source JavaScript library that allows users to create engaging sliders with various hardware-accelerated transition effects. It works on desktop and mobile devices, and users can navigate through the slides with touch-enabled devices. Swiper is free; however, there is a nominal one-time charge to use hardware-accelerated GL transitions. Swiper is available for Javascript, Vue, React, Angular, and WebComponents.


Benefits and Drawbacks of Image Sliders

Image sliders, also known as carousels, generally encourage user interaction. Carousels can use a series of images or media to tell a story, and scrolling through the media can also help your site leave a lasting impression on your users.

While carousels can be visually appealing and help grab attention, including the necessary images consumes resources and degrades browser performance. You can configure Swiper to defer the loading of the images as we have done in this example, but there is going to be extra over-head required to load the series of images.


Swiper Application Example

The following demonstration application will allow you to create your own Swiper carousel. After successfully uploading images, click the carousel radio button and enter the image titles to render a Swiper carousel.

This demo application uses Uppy to upload files to a ColdFusion endpoint using Uppy's bundle XHR option to preserve the chosen order of the files. This application uses the exact code shown below to generate the carousel.


Implementing Swiper


Include the Necessary Files

The example below includes the swiper-bundle.min.js and CSS files via CDN. It does not matter where you include these files if you are using the CDN. Other installation options exist, such as NPM; see Swipers installation page for more information.

I am also including swiper-gl-min.js and CSS to implement hardware-accelerated transition effects. These nifty effects are available when you purchase Swiper's All Access package for 99. This All Access Package also provides an easy-to-use browser or desktop application to create sophisticated Swiper projects. Although running Swiper with these optional hardware-accelerated effects is unnecessary, I think the extra cost is well worth it.


<script src="https://cdn.jsdelivr.net/npm/swiper@10/swiper-bundle.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/swiper@10/swiper-bundle.min.css" />
<!-- Optional libs with GL Effects -->
<script src="/blog/common/libs/swiper/viper/swiper-gl.min.js"></script>
<link rel="stylesheet" href="/blog/common/libs/swiper/viper/swiper-gl.min.css" />

Include Custom CSS to Set the Slide's Appearance

The only necessary CSS is setting the height and width of the carousel like so:


.swiper {
  width: 600px;
  height: 300px;
}

However, many more CSS options are available to fine-tune the slide's appearance.

I use the following custom CSS to fine-tune the appearance. This custom CSS was modified from the initial CSS created by Swiper Studio. I will explain some of the settings below:

  • The global root CSS variables are used to set the pagination color when using pagination. Pagination creates little circles at the bottom of the slides. Here, both the active and inactive colors default to white.
  • The swiper and swiper-slide classes control the basic appearance of the slide. To create a responsive slide, I declare the height in pixels and set the width to 100%. 
  • The flex CSS arguments within the swiper-slide-content class display the arrows, text, and pagination in a column layout within the slide and should not change. The width and height are 100% for the content to fill the slide.
  • The swiper-slide-title and text classes set the font properties for the text near the bottom of the slide. I am placing a subtle drop shadow on the text and using the theme-oriented font that is used for the page title.
  • The swiper-slide-image class is used to fine-tune the image placement within each slide. Here, I am ensuring that the image exceeds the slider boundaries by setting it to 120% so that all images would fit the entire slide.
  • Finally, I set the color of the back and forward chevron images to allow the user to move between the slides.

<style>
	/** Swiper styles **/
	:root {
		--swiper-pagination-color: #FFF;
		--swiper-pagination-bullet-inactive-color: #FFF;
	}

	.swiper {
		user-select: none;
		box-sizing: border-box;
		overflow: hidden;
		width: 100%;
		height: 534px; /*height should always be set */
		padding: 0px 0px;
	}

	.swiper-slide {
		display: flex;
		align-items: center;
		justify-content: center;
		width: 100%;
		height: height:534px;
		position: relative;
		box-sizing: border-box;
		overflow: hidden;
		border-radius: 0px;
	}

	.swiper-slide-content {
		width: 100%; /* Container width */
		height: 100%; /* Container height */
		display: flex;
		flex-direction: column;
		position: relative;
		z-index: 1;
		box-sizing: border-box;
		padding: 48px 48px;
		align-items: flex-start;
		justify-content: flex-end;
		transform: translate3d(0, 0, 0);
	}

	.swiper-slide-title {
		font-family: "Roboto Regular";
		font-size: px;
		font-weight: bold;
		transform-origin: left bottom;
		text-shadow: 4px 8px 16px rgba(0, 0, 0, 0.19); /* The drop shadow should closely mimick the shadow on the main blog layer.*/
	}

	.swiper-slide-text {
		max-width: 640px;
		font-size: px;
		line-height: 1.4;
		transform-origin: left bottom;
		color: ;
	}

	.swiper-slide-title + .swiper-slide-text {
		margin-top: 8px;
	}

	.swiper-slide-image {
		border-radius: 0px;
		position: absolute;
		object-fit: cover;
		left: -10%;
		top: -10%;
		width: 120%;
		height: 120%;
		z-index: 0;
	}
	
	/* back button */
	.swiper-button-next:after,.swiper-button-next:after {
		color: azure
	}
	/* forward button */
	.swiper-button-next:after,.swiper-button-prev:after {
		color: azure
	}
</style>

Initialize Swiper

I typically create a unique JavaScript variable to initialize Swiper, as there may be multiple Swiper instances on a page. Here, my variable is swiper26.

Modules allow the user to customize the functionality of the Swiper widget. I use the premium SwiperGL module, which allows additional hardware-accelerated transition effects. You can use a bundled module package or pick and choose your modules, and you may generally use more than one. Other popular free modules are:

If you choose to implement your custom package, you need to download or import the resources- see https://swiperjs.com/swiper-api#modules for more information.

Many different Swiper interface settings control the interface. I use many of the default settings that Swiper Studio initially created. Many of these settings are intuitive and well-documented. See https://swiperjs.com/types/interfaces/types_swiper_options for more information.

Some of the more important settings that I am using are:

preloadImages (default true) When this setting is set to true, all images must load before the Swiper widget initializes. This forces Swiper to load all images before rendering the image slider. I have experienced some issues when this setting is set to false with the lazy argument also set to true; namely, the preloading spinner image may continue to animate even after all the images have been loaded.

lazy (default false) As of Swiper version 9, this property is deprecated and should not be used! If you want to lazy load your images, apply loading="lazy" for each image. We will cover this again in the next section.

autoplay when set to true, Swiper will autoplay the slides

grabCursor allows the user to move the slides with a touchpad or mouse

effect optional setting. gl allows for hardware-accelerated effects when using the premium Swiper GL module. Otherwise, you can use the following effects:

gl Only used with SwiperGL. Various hardware-accelerated shaders are available when using the premium SwiperGL. You can preview these shaders using our real-time example above.

navigation in this example, navigation simply sets the classes that are used for the forward and reverse buttons

pagination creates the dots at the bottom of the slide that allow the user to navigate to a given slide. 

parallax used to create a parallax effect

speed duration of the transition in ms

and finally, we are allowing the user to use the keyboard


<script>
	var swiper26 = new Swiper(".swiper", {
	modules: [SwiperGL],
	// Disable preloading of images
	preloadImages: false,
	// Enable lazy loading
	lazy: true,
	autoplay: { enabled: true },
	grabCursor: true,
	effect: "gl",
	gl: { shader: "random" },
	navigation: {
		nextEl: '.swiper-button-next',
		prevEl: '.swiper-button-prev',
	},
	pagination: {
		clickable: true,
		dynamicBullets: true,
		el: ".swiper-pagination",
	},
	parallax: { enabled: true },
	speed: 600,
	keyboard: { enabled: true },
	});
</script>

Client-Side HTML

The client-side HTML is straightforward. We have containers using the swiper, the swiper-wrapper, and the swiper-slide CSS classes.

The swiper-slide class contains the content. Each slide has an image, a spinning image pre-loader, and another div element,  containing the textual content. 

Slider images use the swiper-slide-image swiper-gl-image classes and loading="lazy" if you want to lazy load the images (and you should).

The spinning preloader is underneath the images using the swiper-lazy-preloader swiper-lazy-preloader-white classes. You can change the color by adjusting the CSS and remove the preloader by taking out this div. 

The title and body text need to be within their own div elements using the swiper-slide-title and swiper-slide-text CSS classes, respectively. The data-swiper-parallax classes cause a slight delay for the text to be loaded, which helps to create the parallax effect. The title will be delayed by 100ms and the text by 200ms.

Finally, we place the forward and back buttons at the end of the swiper-slide div using swiper-button-next and swiper-button-prev.


<div class="swiper">
	<div class="swiper-wrapper">
		
		<div class="swiper-slide">
			
			<img id="cid26" 
				class="swiper-slide-image swiper-gl-image"  
				src="/blog/enclosures/carousel/1.jpg"
				loading="lazy">
			<div class="swiper-lazy-preloader swiper-lazy-preloader-white"></div>
			<div class="swiper-slide-content">
				<div class="swiper-slide-title" data-swiper-parallax="-100">
					A Grizzly Comes Into the Viewport
				</div>

				<div class="swiper-slide-text" data-swiper-parallax="-200">
					
				</div>
			</div>
			<div class="swiper-button-next"></div>
			<div class="swiper-button-prev"></div>
		</div>
		
		<div class="swiper-slide">
			
			<img id="cid26" 
				class="swiper-slide-image swiper-gl-image"  
				src="/blog/enclosures/carousel/2.jpg"
				loading="lazy">
			<div class="swiper-lazy-preloader swiper-lazy-preloader-white"></div>
			<div class="swiper-slide-content">
				<div class="swiper-slide-title" data-swiper-parallax="-100">
					He looks at me...
				</div>

				<div class="swiper-slide-text" data-swiper-parallax="-200">
					
				</div>
			</div>
			<div class="swiper-button-next"></div>
			<div class="swiper-button-prev"></div>
		</div>
		
		<div class="swiper-slide">
			
			<img id="cid26" 
				class="swiper-slide-image swiper-gl-image"  
				src="/blog/enclosures/carousel/3.jpg"
				loading="lazy">
			<div class="swiper-lazy-preloader swiper-lazy-preloader-white"></div>
			<div class="swiper-slide-content">
				<div class="swiper-slide-title" data-swiper-parallax="-100">
					Yes, go that way!
				</div>

				<div class="swiper-slide-text" data-swiper-parallax="-200">
					
				</div>
			</div>
			<div class="swiper-button-next"></div>
			<div class="swiper-button-prev"></div>
		</div>
		
		<div class="swiper-slide">
			
			<img id="cid26" 
				class="swiper-slide-image swiper-gl-image"  
				src="/blog/enclosures/carousel/4.jpg"
				loading="lazy">
			<div class="swiper-lazy-preloader swiper-lazy-preloader-white"></div>
			<div class="swiper-slide-content">
				<div class="swiper-slide-title" data-swiper-parallax="-100">
					Yes! Go that way!
				</div>

				<div class="swiper-slide-text" data-swiper-parallax="-200">
					
				</div>
			</div>
			<div class="swiper-button-next"></div>
			<div class="swiper-button-prev"></div>
		</div>
		
		<div class="swiper-slide">
			
			<img id="cid26" 
				class="swiper-slide-image swiper-gl-image"  
				src="/blog/enclosures/carousel/5.jpg"
				loading="lazy">
			<div class="swiper-lazy-preloader swiper-lazy-preloader-white"></div>
			<div class="swiper-slide-content">
				<div class="swiper-slide-title" data-swiper-parallax="-100">
					Uh Oh!
				</div>

				<div class="swiper-slide-text" data-swiper-parallax="-200">
					
				</div>
			</div>
			<div class="swiper-button-next"></div>
			<div class="swiper-button-prev"></div>
		</div>
		
		<div class="swiper-slide">
			
			<img id="cid26" 
				class="swiper-slide-image swiper-gl-image"  
				src="/blog/enclosures/carousel/6.jpg"
				loading="lazy">
			<div class="swiper-lazy-preloader swiper-lazy-preloader-white"></div>
			<div class="swiper-slide-content">
				<div class="swiper-slide-title" data-swiper-parallax="-100">
					He turns towards me!
				</div>

				<div class="swiper-slide-text" data-swiper-parallax="-200">
					
				</div>
			</div>
			<div class="swiper-button-next"></div>
			<div class="swiper-button-prev"></div>
		</div>
		
		<div class="swiper-slide">
			
			<img id="cid26" 
				class="swiper-slide-image swiper-gl-image"  
				src="/blog/enclosures/carousel/7.jpg"
				loading="lazy">
			<div class="swiper-lazy-preloader swiper-lazy-preloader-white"></div>
			<div class="swiper-slide-content">
				<div class="swiper-slide-title" data-swiper-parallax="-100">
					I jump on a rock and don't move
				</div>

				<div class="swiper-slide-text" data-swiper-parallax="-200">
					
				</div>
			</div>
			<div class="swiper-button-next"></div>
			<div class="swiper-button-prev"></div>
		</div>
		
		<div class="swiper-slide">
			
			<img id="cid26" 
				class="swiper-slide-image swiper-gl-image"  
				src="/blog/enclosures/carousel/8.jpg"
				loading="lazy">
			<div class="swiper-lazy-preloader swiper-lazy-preloader-white"></div>
			<div class="swiper-slide-content">
				<div class="swiper-slide-title" data-swiper-parallax="-100">
					He growls! Look at the spikes on his hair!
				</div>

				<div class="swiper-slide-text" data-swiper-parallax="-200">
					
				</div>
			</div>
			<div class="swiper-button-next"></div>
			<div class="swiper-button-prev"></div>
		</div>
		
		<div class="swiper-slide">
			
			<img id="cid26" 
				class="swiper-slide-image swiper-gl-image"  
				src="/blog/enclosures/carousel/9.jpg"
				loading="lazy">
			<div class="swiper-lazy-preloader swiper-lazy-preloader-white"></div>
			<div class="swiper-slide-content">
				<div class="swiper-slide-title" data-swiper-parallax="-100">
					Please continue going Bear!
				</div>

				<div class="swiper-slide-text" data-swiper-parallax="-200">
					
				</div>
			</div>
			<div class="swiper-button-next"></div>
			<div class="swiper-button-prev"></div>
		</div>
		
		<div class="swiper-slide">
			
			<img id="cid26" 
				class="swiper-slide-image swiper-gl-image"  
				src="/blog/enclosures/carousel/10.jpg"
				loading="lazy">
			<div class="swiper-lazy-preloader swiper-lazy-preloader-white"></div>
			<div class="swiper-slide-content">
				<div class="swiper-slide-title" data-swiper-parallax="-100">
					Bye Bye!
				</div>

				<div class="swiper-slide-text" data-swiper-parallax="-200">
					
				</div>
			</div>
			<div class="swiper-button-next"></div>
			<div class="swiper-button-prev"></div>
		</div>
		
	</div>

	<div class="swiper-pagination"></div>
</div><!--<div class="swiper">-->