Quantcast
Channel: CodyHouse » Web Components
Viewing all 26 articles
Browse latest View live

Parallax Hero Image

$
0
0
parallax-hero-image A full-width figure element, with floating images distributed in a 3D space. What you can achieve through CSS 3D Transforms is limitless. With power comes responsibility, though. There will be cases when you’ll take full advantage of CSS 3D capabilities. In most projects, though, you can just spice things up a little. Today's nugget is an effect which is getting quite popular and relies on 3D Transforms. In a nutshell, we distributed some images on the z-axis, then we used the mouse as a (fake) 3D camera so that perspective changes while you move the mouse cursor. What we really do is rotating the images in the 3D space according to the mouse position. Since this effect relies on mouse movement, on mobile devices it won't be visible. You can see this cool effect in action on websites like Squarespace and HelloMonday. Image credits: unsplash.com and subtlepatterns.com.

Creating the structure

The main HTML structure is a <figure> element containing our hero image (we used 3 different <img>s) and wrapped in a .cd-background-wrapper element.
<div class="cd-background-wrapper">
	<figure class="cd-floating-background">
		<img src="img/cd-img-1.jpg" alt="image-1">
		<!-- images here -->
	</figure>
</div>
The images used should have the same dimensions.

Adding style

To create the hero image we put the <img> elements one on top of the others: the first one has a static position, while the others are in absolute position; a different translateZ value is assigned to each of them. The idea behind the parallax effect: when user moves his mouse over the hero image, the .cd-floating-background element is rotated (along the X and Y axises)  according to the mouse position. Since the <img> elements  have different translateZ values, a different rotation is perceived for each of them. 3d-parallax-hero-image-explained To properly achieve this effect, we have to make sure that our <img>s are properly positioned in a 3D-space: first, we assign a perspective value to the .cd-background-wrapper, which creates a 3D-space shared by its children; then we assign a transform-style: preserve-3d to the .cd-floating-background so that its children are positioned in a 3D space rather than flattened (as default). TranslateZ does the rest!
@media only screen and (min-width: 1024px) {
  .cd-background-wrapper {
    overflow: hidden;
    perspective: 4000px;
  }

  .cd-floating-background {
    transform-style: preserve-3d;
  }

  .cd-floating-background img:first-child {
    transform: translateZ(50px);
  }

  .cd-floating-background img:nth-child(2) {
    transform: translateZ(290px);
  }

  .cd-floating-background img:nth-child(3) {
    transform: translateZ(400px);
  }
}
About IE: IE9 doesn't support CSS3 3D Transforms while IE10+ doesn't support the transform-style: preserve-3d property. So the parallax effect won't be visible in IE and you'll see a standard image.

Events handling

We bind the initBackground() function to the image load event: this function changes the position property value of the <figure> element from relative to absolute (the  'is-absolute' class is used). At that point, we need to assign a proper height to the .cd-background-wrapper element (since its child is in absolute position, its default height is 0) and proper dimensions to the .cd-floating-background (it has to be bigger than its wrapper - this way rotation won't reveal empty borders). We evaluate the image aspect ratio and the viewport width and assign to the .cd-background-wrapper a height equal to viewportWidth/heroAspectRatio. The .cd-floating-background height and width are proportional to the .cd-background-wrapper ones and its left and top parameters are set so that the image is centered inside its parent. We then bind the mousemove event to the .cd-background-wrapper: the mouse position is evaluated using event.pageX and event.pageY and a corresponding rotateX and rotateY value is assigned to .cd-floating-background. Note: Modernizr doesn't detect preserve-3d support yet. So, in order to target browsers that don't, we used the getPerspective function which assigns a preserve-3d/no-preserve-3d class to the <html> according to browser support (Modernizr - issue 762).

Contact Form

$
0
0
CSS Contact Form A simple and easy to customize contact form. We have been receiving lots of requests about adding a contact form to our library. Here it is! A minimal and customizable snippet to throw a semantic form into your web projects on the fly. There are some optional features (i.e. floating labels) that can be easily removed in case you want the form to be simpler. We included all common form elements like radio buttons, checkboxes, select, error messages etc. All icons are from our Nucleo project. Let's dive into the code!

Creating the structure

Having the HTML structure of a standard form in your pocket is already a way to save time, isn't it? The <form> element contains 2 <fieldset> elements, that split the form in two main blocks. Each form element (that usually contains a <label> + <input>) is wrapped into a simple <div>. This allows us to easily control spacing by setting margins just once. Here is the html structure. You may notice some specific classes, we'll discuss about that in the CSS section.
<form class="cd-form floating-labels">
	<fieldset>
		<legend>Account Info</legend>

		<div class="error-message">
			<p>Please enter a valid email address</p>
		</div>

		<div class="icon">
			<label class="cd-label" for="cd-name">Name</label>
			<input class="user" type="text" name="cd-name" id="cd-name" required>
	    </div> 

	    <!-- ... -->
	</fieldset>

	<fieldset>
		<legend>Project Info</legend>

		<div>
			<h4>Budget</h4>

			<p class="cd-select icon">
				<select class="budget">
					<option value="0">Select Budget</option>
					<option value="1">&lt; $5000</option>
					<option value="2">$5000 - $10000</option>
					<option value="3">&gt; $10000</option>
				</select>
			</p>
		</div> 

		<div>
			<h4>Project type</h4>

			<ul class="cd-form-list">
				<li>
					<input type="radio" name="radio-button" id="cd-radio-1" checked>
					<label for="cd-radio-1">Choice 1</label>
				</li>
					
				<li>
					<input type="radio" name="radio-button" id="cd-radio-2">
					<label for="cd-radio-2">Choice 2</label>
				</li>

				<li>
					<input type="radio" name="radio-button" id="cd-radio-3">
					<label for="cd-radio-3">Choice 3</label>
				</li>
			</ul>
		</div>

		<!-- ... -->

		<div class="icon">
			<label class="cd-label" for="cd-textarea">Project description</label>
  			<textarea class="message" name="cd-textarea" id="cd-textarea" required></textarea>
		</div>

		<div>
	      	<input type="submit" value="Send Message">
	    </div>
	</fieldset>
</form>

Adding style

The CSS is divided in 3 parts: 1) Form, 2) Custom icons and 3) Floating labels. This way, if you want the essential coding part, you can just grab 1) Form. How to add a custom icon: you need to add a class to the element (input/select/textarea) that you want to stylize with the icon (i.e. class .user to the first input element). Secondly you need to add the .icon class to its parent. Finally in CSS you'll define the custom background-image. If the input field is required, you need to define 2 background-images, just like in the example below:
.cd-form .icon input, .cd-form .icon select, .cd-form .icon textarea {
 	padding-left: 54px !important;
}
.cd-form .user {
 	background: url("../img/cd-icon-user.svg") no-repeat 16px center;
}
.cd-form [required].user {
 	background: url("../img/cd-icon-user.svg") no-repeat 16px center, 
 				url("../img/cd-required.svg") no-repeat top right;
}
Floating labels are activated through the .floating-labels class added to the .cd-form element. In case you never heard of this UX pattern, it was first introduced by Matt D. Smith. He also explained how he came up with this idea in this interesting article. In my opinion, it's a great UX solution: it allows you to use labels as placeholders at first, then turning them into animated labels once the user starts typing. This way the user has always a clue of what kind of information has been provided already. You'll notice in CSS the .floating-labels class derives from the .js class, which is added by Modernizr when javascript is supported by the browser. This way if javascript is disabled by the browser/user, the form is still accessible with standard labels (the .floating-labels class produces no effect). In order to stylize an obligatory field, we took advantage of the required boolean HTML5 attribute. While the error is just a class added to the form element.
.cd-form [required] {
 	background: url("../img/cd-required.svg") no-repeat top right;
}

.cd-form .error {
	border-color: #e94b35 !important;
}
Another interesting point is the way we created custom radio and check buttons. You'll find the source code pretty straightforward. In a nutshell, we set position: absolute; and opacity: 0; for the radio and check input elements, and replaced them with custom ::before and ::after pseudo elements of the <label>.

Events handling

Javascript has been used to activate the floating labels. If a .floating-labels element exists in the DOM, we initialize the floatLabels() function: it grabs the form input fields (targeted as next elements of the .cd-label) and binds the checkVal() function to the keyup() event to detect if the user has started typing.
if( $('.floating-labels').length > 0 ) floatLabels();

function floatLabels() {
	var inputFields = $('.floating-labels .cd-label').next();
	
	inputFields.each(function(){
		var singleInput = $(this);
		
		singleInput.keyup(function(){
			checkVal(singleInput);	
		});
	});
}
The checkVal() function checks the input value: if not empty, it adds the float class to its previous .cd-label element, otherwise it removes it.

Hero Slider

$
0
0
hero slider A full-width, responsive and easy to customize slideshow. It is a common approach to fill in the intro section of a website with a slideshow: you're trying to show the users as much as you can above the fold, yet you want to deliver this information in an organized and clean way.  Therefore we built for you a ready-to-use jQuery slider, with some built in options like video/image backgrounds and different text alignments. In an attempt to increase user engagement, we replaced the "navigation arrows" with buttons. The difference is: buttons have a title, a hint about what kind of content to expect. Arrows just tell users "you can switch slide". Assets:

Creating the structure

The HTML is structured in 2 main elements: an unordered list (ul.cd-hero-slider) containing the slides, and a div.cd-slider-nav, containing the slider navigation and the span.cd-marker (used to create the marker for the selected item in the navigation).
<section class="cd-hero">
	<ul class="cd-hero-slider">
		<li class="selected">
			<div class="cd-full-width">
				<h2><!-- title here  --></h2>
				<p><!-- description here --></p>
				<a href="#0" class="cd-btn"><!-- btn text here --></a>
			</div> <!-- .cd-full-width -->
		</li>

		<!-- othe slides here -->

	</ul> <!-- .cd-hero-slider -->

	<div class="cd-slider-nav">
		<nav>
			<span class="cd-marker item-1"></span>
			
			<ul>
				<li class="selected"><a href="#0">Intro</a></li>
				<li><a href="#0">Tech 1</a></li>
				<!-- other navigation items here -->
			</ul>
		</nav> 
	</div> <!-- .cd-slider-nav -->
</section> <!-- .cd-hero -->

Adding style

The slider structure is pretty straightforward: all the slides are translated to the right, outside the viewport (translateX(100%)); the .selected class is added to the visible slide to move it back into the viewport (translateX(0)), while the .move-left class is used to translate a slide to the left (translateX(-100%)). To achieve the smooth animation, we used CSS3 Transitions applied to the .selected and the .is-moving elements: when a new slide is selected, the .is-moving class is assigned to the slide moving outside the viewport, while the .selected class is assigned to the selected slide.
.cd-hero-slider li {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  transform: translateX(100%);
}
.cd-hero-slider li.selected {
  /* this is the visible slide */
  position: relative;
  transform: translateX(0);
}
.cd-hero-slider li.move-left {
  /* slide hidden on the left */
  transform: translateX(-100%);
}
.cd-hero-slider li.is-moving, .cd-hero-slider li.selected {
  /* the is-moving class is assigned to the slide which is moving outside the viewport */
  transition: transform 0.5s;
}
About the single slide animation: on big devices (viewport width more than 768px), we decided to spice up the entrance effect animating the single slide elements (.cd-half-width and .cd-full-width), changing their opacity and transform properties. The .from-left and .from-right classes are used to detect if the .selected slide is entering the viewport from the left or from the right, in order to trigger a different animation according to the entrance direction. For this effect to properly work, we used a different animation-delay value for each animated element. For the .cd-half-width elements, for example:
@media only screen and (min-width: 768px) {
  .cd-hero-slider .cd-half-width {
    opacity: 0;
    transform: translateX(40px);
  }
  .cd-hero-slider .move-left .cd-half-width {
    transform: translateX(-40px);
  }
  .cd-hero-slider .selected .cd-half-width {
    /* this is the visible slide */
    opacity: 1;
    transform: translateX(0);
  }
  .cd-hero-slider .is-moving .cd-half-width {
    /* this is the slide moving outside the viewport 
    wait for the end of the transition on the <li> parent before set opacity to 0 and translate to 40px/-40px */
    transition: opacity 0s 0.5s, transform 0s 0.5s;
  }
  .cd-hero-slider li.selected.from-left .cd-half-width:nth-of-type(2),
  .cd-hero-slider li.selected.from-right .cd-half-width:first-of-type {
    /* this is the selected slide - different animation if it's entering from left or right */
    transition: opacity 0.4s 0.2s, transform 0.5s 0.2s;
  }
  .cd-hero-slider li.selected.from-left .cd-half-width:first-of-type,
  .cd-hero-slider li.selected.from-right .cd-half-width:nth-of-type(2) {
    /* this is the selected slide - different animation if it's entering from left or right */
    transition: opacity 0.4s 0.4s, transform 0.5s 0.4s;
  }
}

Events handling

The video used as background for one of the slides is not inserted directly into the HTML but loaded only if the device width is bigger than 768px; this way the video won't be loaded on mobile devices. The data-video of the selected slide is used to retrieve the video url. You may consider doing the same for the <img> elements inside the .cd-img-container (which is hidden on mobile devices). Besides, we used jQuery to implement the slideshow functionality: when user clicks one of the list items of the .cd-slider-nav tab, we detect the position of the selected item  (using the index() function) and update the slider (using the nextSlide() or prevSlide() functions according to this position) and the span.cd-marker position.
$('.cd-slider-nav li').on('click', function(event){
	event.preventDefault();
	var selectedItem = $(this);
	if(!selectedItem.hasClass('selected')) {
		// if it's not already selected
		var selectedPosition = selectedItem.index(),
			activePosition = $('.cd-hero-slider .selected').index();
		if( activePosition < selectedPosition) {
			nextSlide($('.cd-hero-slider'), $('.cd-slider-nav'), selectedPosition);
		} else {
			prevSlide($('.cd-hero-slider'), $('.cd-slider-nav'), selectedPosition);
		}
		
		updateNavigationMarker(selectedPosition+1);
	}
});

Mega Dropdown

$
0
0
mega dropdown A responsive and easy to customise mega-dropdown component. One of the most challenging part when you’re working on a web projects with lots of content is to make it easy for a user to navigate through this content. One example we can all think of is Amazon: infinite categories, each one with its own sub-categories…that’s why they currently provide an easy-to-access navigation, in the form of a mega-dropdown element on the top-right corner of the page. We’ve been working on a similar concept, a responsive mega dropdown component with sub-categories. Here is a quick animation we put together to show you our mobile vs desktop approach: dropdown animation As you can notice from the demo, our dropdown is activated with a tap/click. We could have achieved the same thing using a :hover state instead, no need for js (we do provide a :hover fallback in case javascript is disabled). However these decisions should be based on what we thing is the best user experience. Users generally expect to click to access new content, while :hover effects mostly detect a “potential action”. This is why we preferred click over :hover state. In case you disagree, switching from one approach to the other is a piece of cake ;) Icons: Nucleo Library

Creating the structure

The HTML is structured in 2 main elements: the <header>, containing the dropdown (.cd-dropdown-wrapper), and the <main> for all the main content. The .cd-dropdown-wrapper containes a .cd-dropdown-trigger, to trigger the dropdown, and a .cd-dropdown, which is composed by nested unordered lists.
<header>
	<div class="cd-dropdown-wrapper">
		<a class="cd-dropdown-trigger" href="#0">Dropdown</a>
		<nav class="cd-dropdown">
			<h2>Title</h2>
			<a href="#0" class="cd-close">Close</a>
			<ul class="cd-dropdown-content">
				<li>
					<form class="cd-search">
						<input type="search" placeholder="Search...">
					</form>
				</li>
				<li class="has-children">
					<a href="#0">Clothing</a>

					<ul class="cd-secondary-dropdown is-hidden">
						<li class="go-back"><a href="#0">Menu</a></li>
						<li class="see-all"><a href="#0">All Clothing</a></li>
						<li class="has-children">
							<a href="#0">Accessories</a>

							<ul class="is-hidden">
								<li class="go-back"><a href="#0">Clothing</a></li>
								<li class="see-all"><a href="#0">All Accessories</a></li>
								<li class="has-children">
									<a href="#0">Beanies</a>

									<ul class="is-hidden">
										<li class="go-back"><a href="#0">Accessories</a></li>
										<li class="see-all"><a href="#0">All Benies</a></li>
										<li><a href="#0">Caps &amp; Hats</a></li>
										<!-- other list items here -->
									</ul>
								</li>
								<li class="has-children">
									<a href="#0">Caps &amp; Hats</a>

									<ul class="is-hidden">
										<li class="go-back"><a href="#0">Accessories</a></li>
										<li class="see-all"><a href="#0">All Caps &amp; Hats</a></li>
										<li><a href="#0">Beanies</a></li>
										<!-- other list items here -->
									</ul>
								</li>
								<li><a href="#0">Glasses</a></li>
								<!-- other list items here -->
							</ul>
						</li>

						<li class="has-children">
							<!-- other list items here -->
						</li>

						<li class="has-children">
							<!-- other list items here -->
						</li>

						<li class="has-children">
							<!-- other list items here -->
						</li>
					</ul> <!-- .cd-secondary-dropdown -->
				</li> <!-- .has-children -->

				<li class="has-children">
					<!-- other list items here -->
				</li> <!-- .has-children -->

				<li class="has-children">
					<!-- other list items here -->
				</li> <!-- .has-children -->

				<li class="cd-divider">Divider</li>

				<li><a href="#0">Page 1</a></li>
				<!-- other list items here -->

			</ul> <!-- .cd-dropdown-content -->
		</nav> <!-- .cd-dropdown -->
	</div> <!-- .cd-dropdown-wrapper -->
</header>

<main class="cd-main-content">
	<!-- your content here -->
</main>

Adding style

For mobile devices, the basic idea was to let the user focus totally on the dropdown content, once it has been activated. This is why we assigned a fixed position to the dropdown, and set its width and height to 100%. By default, it is hidden right above the viewport (translateY(-100%)). When the user clicks the trigger element, the .dropdown-is-active class is added to the dropdown which is translated back into the viewport.
.cd-dropdown {
  position: fixed;
  z-index: 1;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  transform: translateY(-100%);
  transition: transform 0.5s;
}
.cd-dropdown.dropdown-is-active {
  transform: translateY(0);
}
When user selects a new sublevel in the dropdown, the visible items are translated to the left outside the viewport (using the .move-out class),  while the new items slide back into the viewport (removing the class .is-hidden class from their <ul> parent element).
.cd-dropdown-content.is-hidden, .cd-dropdown-content ul.is-hidden {
  /* push the secondary dropdown items to the right */
  transform: translateX(100%);
}

.cd-dropdown-content.move-out > li > a, .cd-dropdown-content ul.move-out > li > a {
  /* push the dropdown items to the left when secondary dropdown slides in */
  transform: translateX(-100%);
}
On bigger devices (viewport width bigger than 1024px), instead, there's enough space to place content side by side, with no need to replace the visible content.
@media only screen and (min-width: 1024px) {
  .cd-dropdown {
    position: absolute;
    top: 100%;
    /* reset style*/
    height: auto;
    width: auto;
    opacity: 0;
    visibility: hidden;
    transform: translateY(30px);
    transition: opacity 0.3s 0s, visibility 0s 0.3s, transform 0.3s 0s;
  }
  .cd-dropdown.dropdown-is-active {
    visibility: visible;
    opacity: 1;
    transform: translateY(0);
    transition: opacity 0.3s 0s, visibility 0.3s 0s, transform 0.3s 0s;
  }

  .cd-dropdown-content {
    /* reset mobile style */
    position: static;
    height: auto;
    width: 280px;
  }
  .cd-dropdown-content .cd-secondary-dropdown, .cd-dropdown-content .cd-dropdown-gallery, .cd-dropdown-content .cd-dropdown-icons {
    transform: translateX(0);
    left: 100%;
    height: auto;
  }
  .cd-dropdown-content .cd-secondary-dropdown.is-hidden, .cd-dropdown-content .cd-dropdown-gallery.is-hidden, .cd-dropdown-content .cd-dropdown-icons.is-hidden {
    /* reset mobile style */
    transform: translateX(0);
  }
  .cd-dropdown-content > .has-children > ul {
    visibility: hidden;
  }
  .cd-dropdown-content > .has-children:hover > ul {
    /* when hover over .cd-dropdown-content items - show subnavigation */
    visibility: visible;
  }
  .cd-dropdown-content > .has-children:hover > .cd-secondary-dropdown > li > ul {
    /* if .cd-secondary-dropdown is visible - show also subnavigation */
    visibility: visible;
  }
}

Events handling

We didn’t do a lot in jQuery, apart from listening to the click event on specific elements (e.g. .cd-dropdown-trigger, .go-back) and adding/removing classes accordingly.

Product Tour

$
0
0
product-tour A responsive tour snippet, with a step-by-step guide to help users understand how to use your website. Onboarding processes are essential to let users familiarize with your website/app functionalities as soon as possible. A common user case is the “free trial”: if a user is taking your app for a spin, he’s going to gather as many information as he can in few minutes, before deciding whether your app is worth paying for. You don’t want one of these info to be “how the hell does this work”? The easiest way to improve user experience is to build a simple step-by-step intro tour. Today we release a handy tour snippet powered by CSS and jQuery, characterized by a user experience that changes according to the device size. Here is a quick animation that shows the difference between the tour on small devices vs bigger ones: tour animation

Creating the structure

The HTML structure is composed by an unordered list: each list item contains a .cd-more-info (step title, brief description and image for mobile version) and a <span> element used to create the dot indicator.
<body>
	<button id="cd-tour-trigger">Start tour</button>

	<ul class="cd-tour-wrapper">
		<li class="cd-single-step">
			<span>Step 1</span>

			<div class="cd-more-info bottom">
				<h2>Step Number 1</h2>
				<p><!--  description here  --></p>
				<img src="img/step-1.png" alt="step 1">
			</div>
		</li> <!-- .cd-single-step -->

		<!-- other steps here -->
	</ul> <!-- .cd-tour-wrapper -->

</body>
Note that the .cd-nav element (tour navigation visible in each step) is not directly inserted in the html but created using jQuery. Also, the .cd-app-screen element has been used to create the fake background app, so you can remove it from the html (and the related style) when using it in your live application.

Adding style

On mobile devices, the tour is open as a modal window (with a smooth scale effect achieved adding a CSS3 transition to the scale property of the .cd-single-step list items): each step shows a title, a description and an image representing the feature being displayed. The css for this version is pretty straightforward (you can give a look at the code for more details/comments). On desktop devices (viewport width bigger than 1100px), we assigned a position to each .cd-single-step list item (we used percentage rather than px so that they preserve their position regardless of the screen size): the <span> element inside each list item is used to create the dot indicator, while the pulse effect is created using the list item ::after pseudo-element and animating its box-shadow.
@media only screen and (min-width: 1100px) {
  .cd-single-step {
    position: absolute;
    border-radius: 50%;
    visibility: hidden;
    transition: visibility 0s 0.4s;
  }
  .cd-single-step:nth-of-type(1) {
    /* set tour points positions */
    bottom: 40%;
    right: 30%;
  }

  /*define here all the other list items position values*/
 
  .cd-single-step > span {
    /* dot indicator - visible on desktop version only */
    width: 10px;
    height: 10px;
    background: #ff962c;
    transform: scale(0);
    transition: transform 0.4s;
    /* replace text with background images */
    overflow: hidden;
    text-indent: 100%;
    white-space: nowrap;
  }
  .cd-single-step .cd-more-info {
    position: absolute;
    opacity: 0;
    transition: opacity 0.4s;
  }
  .cd-single-step.is-selected {
    /* visible step */
    visibility: visible;
    transition: visibility 0s 0s;
  }
  .cd-single-step.is-selected > span {
    transform: scale(1);
  }
  .cd-single-step.is-selected::after {
    animation: cd-pulse 2s infinite;
    animation-delay: 0.5s;
  }
  .cd-single-step.is-selected .cd-more-info {
    opacity: 1;
  }
}

@keyframes cd-pulse {
  0% {
    box-shadow: 0 0 0 0 #ff962c;
  }
  100% {
    box-shadow: 0 0 0 20px rgba(255, 150, 44, 0);
  }
}
4 different classes have been defined to control the position of the tooltip relative to the dot indicator (.top, .bottom, .left and .right, to be assigned to the .cd-more-info element).

Events handling

We used jQuery to implement the tour navigation functionality (with keyboard, touch swipe and previous/next navigation). Besides, the createNavigation() function has been implemented to create the tour navigation element (.cd-nav) and insert it into the DOM.

Breadcrumbs & Multi-Step Indicator

$
0
0
css-breadcrumbs-multisteps-featured A handy snippet to create responsive CSS breadcrumbs or multi-step indicators with ease. Users obviously don't like to feel lost while they navigate the content of our website. This is why we introduced UX patterns to show them how they got to a specific page (breadcrumbs) and what comes next (multi-steps indicators). Since both breadcrumbs and multi-step indicators share a similar structure (a simple list of items), we created a handy snippet to create and customize them with a preset of time-saving classes. Icons from our Nucleo library.

Creating the structure

The HTML structure is very basic: an ordered list of items, wrapped into a <nav> element.
<nav>
	<ol class="cd-breadcrumb">
		<li><a href="#0">Home</a></li>
		<li><a href="#0">Gallery</a></li>
		<li><a href="#0">Web</a></li>
		<li class="current"><em>Project</em></li>
	</ol>
</nav>

Adding style & Guidelines

We created 2 main classes for the <ol> element: .cd-breadcrumb and .cd-multi-steps. Although they share a similar style, we wanted to differentiate the two web components since they serve a different purpose. For the basic version, we used the ::after pseudo-element of the list items to create the separator element:
.cd-breadcrumb li::after, .cd-multi-steps li::after {
  display: inline-block;
  content: '\00bb';
  margin: 0 .6em;
  color: #959fa5;
}
We created a preset of CSS classes - to be added to the <ol> element, that modify the style of the web component. For example: if you want to use a custom icon as a separator between items (example number 2), just use the .custom-separator class.
<nav>
	<ol class="cd-breadcrumb custom-separator">
		<li><a href="#0">Home</a></li>
		<li><a href="#0">Gallery</a></li>
		<li><a href="#0">Web</a></li>
		<li class="current"><em>Project</em></li>
	</ol>
</nav>
Then remember to update the background image of ::after pseudo-element of the list item:
.cd-breadcrumb.custom-separator li::after, 
.cd-multi-steps.custom-separator li::after {
  /* replace the default separator with a custom icon */
  content: '';
  height: 16px;
  width: 16px;
  background: url(../img/cd-custom-separator.svg) no-repeat center center;
  vertical-align: middle;
}
The .custom-icons class is for adding custom icons before each list item. Once again you need to update the CSS according to the images you want to use. In our demo we used a .svg file as image sprites:
.cd-breadcrumb.custom-icons li > *::before, 
.cd-multi-steps.custom-icons li > *::before {
  /* add a custom icon before each item */
  content: '';
  display: inline-block;
  height: 20px;
  width: 20px;
  margin-right: .4em;
  margin-top: -2px;
  background: url(../img/cd-custom-icons-01.svg) no-repeat 0 0;
  vertical-align: middle;
}
.cd-breadcrumb.custom-icons li:not(.current):nth-of-type(2) > *::before, 
.cd-multi-steps.custom-icons li:not(.current):nth-of-type(2) > *::before {
  /* change custom icon using image sprites */
  background-position: -20px 0;
}
.cd-breadcrumb.custom-icons li:not(.current):nth-of-type(3) > *::before, 
.cd-multi-steps.custom-icons li:not(.current):nth-of-type(3) > *::before {
  background-position: -40px 0;
}
.cd-breadcrumb.custom-icons li:not(.current):nth-of-type(4) > *::before, 
.cd-multi-steps.custom-icons li:not(.current):nth-of-type(4) > *::before {
  background-position: -60px 0;
}
.cd-breadcrumb.custom-icons li.current:first-of-type > *::before, 
.cd-multi-steps.custom-icons li.current:first-of-type > *::before {
  /* change custom icon for the current item */
  background-position: 0 -20px;
}
.cd-breadcrumb.custom-icons li.current:nth-of-type(2) > *::before, 
.cd-multi-steps.custom-icons li.current:nth-of-type(2) > *::before {
  background-position: -20px -20px;
}
.cd-breadcrumb.custom-icons li.current:nth-of-type(3) > *::before, 
.cd-multi-steps.custom-icons li.current:nth-of-type(3) > *::before {
  background-position: -40px -20px;
}
.cd-breadcrumb.custom-icons li.current:nth-of-type(4) > *::before, 
.cd-multi-steps.custom-icons li.current:nth-of-type(4) > *::before {
  background-position: -60px -20px;
}
The .triangle class generates CSS triangles after each list item. To create the separation between items we used a trick we found on CSS-Tricks.
  .cd-breadcrumb.triangle li::after, 
  .cd-breadcrumb.triangle li > *::after {
    /* 
    	li > *::after is the colored triangle after each item
    	li::after is the white separator between two items
    */
    content: '';
    position: absolute;
    top: 0;
    left: 100%;
    content: '';
    height: 0;
    width: 0;
    /* 48px is the height of the <a> element */
    border: 24px solid transparent;
    border-right-width: 0;
    border-left-width: 20px;
  }
  .cd-breadcrumb.triangle li::after {
    /* this is the white separator between two items */
    z-index: 1;
    -webkit-transform: translateX(4px);
    -moz-transform: translateX(4px);
    -ms-transform: translateX(4px);
    -o-transform: translateX(4px);
    transform: translateX(4px);
    border-left-color: #ffffff;
    /* reset style */
    margin: 0;
  }
  .cd-breadcrumb.triangle li > *::after {
    /* this is the colored triangle after each element */
    z-index: 2;
    border-left-color: inherit;
  }
  .cd-breadcrumb.triangle li:last-of-type::after, 
  .cd-breadcrumb.triangle li:last-of-type > *::after {
    /* hide the triangle after the last step */
    display: none;
  }
Other classes to keep in mind are: .text-center, .text-top and .text-bottom to be used with the .cd-multi-steps class to set the position of the labels, and .count if you want to add a counter to the multi-steps indicator.
<nav>
	<ol class="cd-multi-steps text-bottom count">
		<li class="visited"><a href="#0">Cart</a></li>
		<li class="visited" ><a href="#0">Billing</a></li>
		<li class="current"><em>Delivery</em></li>
		<li><em>Review</em></li>
	</ol>
</nav>
The easiest way to understand how this resource works is by checking the source files: most classes can be combined, and we covered all possible combinations in the 9 examples of the demo. Enjoy!

Animated SVG Hero Slider

$
0
0
animated-svg-hero-slider A full page slider, with animated SVG elements used as transition effects. While surfing the web for inspiration, we bumped into the beautifully-designed Honda HR-V website. When you navigate from a section to the other, the transition is embellished by an animated shape - created using a <canvas> element. We decided to create something similar, but instead of using canvas, we played with SVG. Also, instead of creating a vertical layout that would require forced scrolling to see the animation, we turned the whole resource into a hero slider. Resources used:

Creating the structure

The HTML is structured in 3 main elements: an unordered list (ul.cd-slider) containing the slides, an ordered list (ol.cd-slider-navigation) for the slider navigation, and a div.cd-svg-cover, used to create the animated shape visible when you switch from one slide to the next one.
<section class="cd-slider-wrapper">
	<ul class="cd-slider">
		<li class="visible">
			<div>
				<h2>Animated SVG Slider</h2>
				<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Animi, explicabo.</p>
				<a href="#0" class="cd-btn">Article &amp; Download</a>
			</div>
		</li>
			
		<li>
			<!-- slide content here -->
		</li>

		<!-- additional slides here -->
	</ul> <!-- .cd-slider -->

	<ol class="cd-slider-navigation">
		<li class="selected"><a href="#0"><em>Item 1</em></a></li>
		<li><a href="#0"><em>Item 2</em></a></li>
		<li><a href="#0"><em>Item 3</em></a></li>
		<li><a href="#0"><em>Item 4</em></a></li>
	</ol> <!-- .cd-slider-navigation -->
	
	<div class="cd-svg-cover" data-step1="M1402,800h-2V0.6c0-0.3,0-0.3,0-0.6h2v294V800z" data-step2="M1400,800H383L770.7,0.6c0.2-0.3,0.5-0.6,0.9-0.6H1400v294V800z" data-step3="M1400,800H0V0.6C0,0.4,0,0.3,0,0h1400v294V800z" data-step4="M615,800H0V0.6C0,0.4,0,0.3,0,0h615L393,312L615,800z" data-step5="M0,800h-2V0.6C-2,0.4-2,0.3-2,0h2v312V800z" data-step6="M-2,800h2L0,0.6C0,0.3,0,0.3,0,0l-2,0v294V800z" data-step7="M0,800h1017L629.3,0.6c-0.2-0.3-0.5-0.6-0.9-0.6L0,0l0,294L0,800z" data-step8="M0,800h1400V0.6c0-0.2,0-0.3,0-0.6L0,0l0,294L0,800z" data-step9="M785,800h615V0.6c0-0.2,0-0.3,0-0.6L785,0l222,312L785,800z" data-step10="M1400,800h2V0.6c0-0.2,0-0.3,0-0.6l-2,0v312V800z">
		<svg height='100%' width="100%" preserveAspectRatio="none" viewBox="0 0 1400 800">
			<title>SVG cover layer</title>
			<desc>an animated layer to switch from one slide to the next one</desc>
			<path id="cd-changing-path" d="M1402,800h-2V0.6c0-0.3,0-0.3,0-0.6h2v294V800z"/>
		</svg>
	</div> <!-- .cd-svg-cover -->
</section> <!-- .cd-slider-wrapper -->

Adding style

By default, all the slides have an opacity: 0, are in absolute position and are placed one on top of the others (top: 0 and left:0). The .visible class is added to the selected slide to make it visible (opacity: 1).
.cd-slider-wrapper {
  position: relative;
}

.cd-slider > li {
  position: absolute;
  top: 0;
  left: 0;
  opacity: 0;
}
.cd-slider > li.visible {
  /* selected slide */
  position: relative;
  z-index: 2;
  opacity: 1;
}

Events handling

To animate the SVG, we animated the 'd' attribute of the path element inside the .cd-svg-container. First of all, we had to define the different steps of the animation (in our case, 5 steps to animate from a slide to the next one and 5 more steps to animate from a slide to the previous one); basically we had to create 10 different svg paths elements (all with the same number of anchor points for the animation to properly work), as shown in the following screenshot taken from the Illustrator file (note that some steps seem empty, but they all contain a path). illustrator-close-up Once the paths have been defined, we added to the .cd-svg-cover a data-stepn attribute (one for each step) equal to the 'd' attribute of the defined path (to easily retrieve it with JavaScript). We then used the animate() method provided by Snap.svg to animate from a path to the next one:
var svgCoverLayer = $('.cd-slider-wrapper').find('div.cd-svg-cover'),
	svgPath = Snap('#cd-changing-path'),
	path1 = svgCoverLayer.data('step1');

svgPath.animate({'d': path2}, 300, customMinaAnimation, function(){
	//...
});
The easing function is a custom cubic-bezier function; unfortunately this is something wich is not available by default in Snap.svg, but you can create a custom timing function from your custom cubic-bezier (here's a StackOverflow post that covers it in details). Illustrator trick: for this technique to work, you need <path> elements. In Illustrator, if you use only straight lines, a <polygon> element is created. To convert it to a <path>, you can add a border-radius to one of anchor points. border-radius-trick

Animated SVG Image Slider

$
0
0
animated-svg-image-slider A simple, responsive carousel with animated SVG paths used as transition effects. Last week we’ve been experimenting with SVG paths to animate the content of a full-page hero slider. Today we use the same technique to create a responsive carousel. This time, though, we used SVG paths to directly clip the slide images, with no need to show an intermediate layer. Images: Unsplash

Creating the structure

The HTML structure is composed by an unordered list (ul.cd-slider), containing the slides, and two additional list elements ( ul.cd-slider-navigation and ol.cd-slider-controls) for the slider navigations. Each list item inside the ul.cd-slider is composed by an svg containing a <clipPath> element (used to change the clipping area of the slide image) and an <image> element (whose clip-path url attribute is the <clipPath> id).
<div class="cd-slider-wrapper">
	<ul class="cd-slider" data-step1="M1402,800h-2V0.6c0-0.3,0-0.3,0-0.6h2v294V800z" data-step2="M1400,800H383L770.7,0.6c0.2-0.3,0.5-0.6,0.9-0.6H1400v294V800z" data-step3="M1400,800H0V0.6C0,0.4,0,0.3,0,0h1400v294V800z" data-step4="M-2,800h2L0,0.6C0,0.3,0,0.3,0,0l-2,0v294V800z" data-step5="M0,800h1017L629.3,0.6c-0.2-0.3-0.5-0.6-0.9-0.6L0,0l0,294L0,800z" data-step6="M0,800h1400V0.6c0-0.2,0-0.3,0-0.6L0,0l0,294L0,800z">
		<li class="visible">
			<div class="cd-svg-wrapper">
				<svg viewBox="0 0 1400 800">
                    <title>Aimated SVG</title>
					<defs>
						<clipPath id="cd-image-1">
							<path id="cd-changing-path-1" d="M1400,800H0V0.6C0,0.4,0,0.3,0,0h1400v294V800z"/>
						</clipPath>
					</defs>
					
					<image height='800px' width="1400px" clip-path="url(#cd-image-1)" xlink:href="img/img-1.jpg"></image>
				</svg>
			</div> <!-- .cd-svg-wrapper -->
		</li>

		<li>
			<div class="cd-svg-wrapper">
				<svg viewBox="0 0 1400 800">
					<!-- svg content here -->
				</svg>
			</div> <!-- .cd-svg-wrapper -->
		</li>

		<!-- other list items here -->
		
	</ul> <!-- .cd-slider -->

	<ul class="cd-slider-navigation">
		<li><a href="#0" class="next-slide">Next</a></li>
		<li><a href="#0" class="prev-slide">Prev</a></li>
	</ul> <!-- .cd-slider-navigation -->

	<ol class="cd-slider-controls">
		<li class="selected"><a href="#0"><em>Item 1</em></a></li>
		<li><a href="#0"><em>Item 2</em></a></li>
		<!-- other list items here -->
	</ol> <!-- .cd-slider-controls -->
</div> <!-- .cd-slider-wrapper -->

Adding style

The slider structure is quite basic: all slides have an opacity: 0, are in absolute position and are placed one on top of the other (top: 0 and left:0). The .visible class is added to the selected slide (at the end of the clipping animation) to make it visible, while the .is-animating class is added to the list item during the clipping animation (z-index: 3 so that it is over the li.visible item). Note: we had to use the Padding Hack to make the svg responsive (IE assumes svg height to be 150px if you don't explicitly define it). Basically, we set the div.cd-svg-wrapper height to 0 and its padding-bottom to 57.15% (to preserve svg proportion, in our case 800/1400), and set the svg height and width to 100%.
.cd-slider > li {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  opacity: 0;
}
.cd-slider > li.visible {
  position: relative;
  z-index: 2;
  opacity: 1;
}
.cd-slider > li.is-animating {
  z-index: 3;
  opacity: 1;
}
.cd-slider .cd-svg-wrapper {
  /* using padding Hack to fix bug on IE - svg height not properly calculated */
  height: 0;
  padding-bottom: 57.15%;
}
.cd-slider svg {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

Events handling

To animate the slide image clipping area, we animated the 'd' attribute of the <path> element inside the <clipPath>. First of all, we had to define the different steps of our animation: we used the same process described in the Animated SVG Hero Slider article (Events handling section); but in this case, we needed only 6 steps (3 steps to animate from a slide to the next one and 3 more steps to animate from a slide to the previous one). Once defined the paths, we added to the .cd-slider a data-stepn attribute (one for each step) equal to the 'd' attribute of the defined path (to easily retrieve it with JavaScript). We then used the animate() method provided by Snap.svg to animate the path element.
clipPath.attr('d', path1).animate({'d': path2}, duration, firstCustomMinaAnimation, function(){
	clipPath.animate({'d': path3}, duration, secondCustomMinaAnimation, function(){
		oldSlide.removeClass('visible');
		newSlide.addClass('visible').removeClass('is-animating');
	});
});
Besides, we implemented a basic slider for the image gallery (with keyboard and touch swipe navigation, previous/next and dots navigation).

SVG Modal Window

$
0
0
svg-modal-window A simple modal window with an animated SVG background. We’ve been experimenting lately with SVG path animations, creating transitions for our image slider and hero slider. Today’s tutorial shows you how to animate at once multiple SVG paths to create a stylish background effect for a modal window. Inspiration: UI8 Nav on Dribbble

Creating the structure

The HTML structure is composed by 2 main elements: a <section>, used to wrap the action button (#modal-trigger), and a div.cd-modal, the modal window, containing the modal content (.cd-modal-content) and the div.cd-svg-bg, used to create the background covering effect.
<main class="cd-main-content">
	<section class="center">
		<h1>SVG Modal Window</h1>
		<a href="#0" class="cd-btn" id="modal-trigger" data-type="cd-modal-trigger">Fire Modal Window</a>
	</section>
</main> <!-- .cd-main-content -->

<div class="cd-modal" data-modal="modal-trigger">
	<div class="cd-svg-bg" data-step1="M-59.9,540.5l-0.9-1.4c-0.1-0.1,0-0.3,0.1-0.3L864.8-41c0.1-0.1,0.3,0,0.3,0.1l0.9,1.4c0.1,0.1,0,0.3-0.1,0.3L-59.5,540.6 C-59.6,540.7-59.8,540.7-59.9,540.5z" data-step2="M33.8,690l-188.2-300.3c-0.1-0.1,0-0.3,0.1-0.3l925.4-579.8c0.1-0.1,0.3,0,0.3,0.1L959.6,110c0.1,0.1,0,0.3-0.1,0.3 L34.1,690.1C34,690.2,33.9,690.1,33.8,690z" data-step3="M-465.1,287.5l-0.9-1.4c-0.1-0.1,0-0.3,0.1-0.3L459.5-294c0.1-0.1,0.3,0,0.3,0.1l0.9,1.4c0.1,0.1,0,0.3-0.1,0.3 l-925.4,579.8C-464.9,287.7-465,287.7-465.1,287.5z" data-step4="M-329.3,504.3l-272.5-435c-0.1-0.1,0-0.3,0.1-0.3l925.4-579.8c0.1-0.1,0.3,0,0.3,0.1l272.5,435c0.1,0.1,0,0.3-0.1,0.3 l-925.4,579.8C-329,504.5-329.2,504.5-329.3,504.3z" data-step5="M341.1,797.5l-0.9-1.4c-0.1-0.1,0-0.3,0.1-0.3L1265.8,216c0.1-0.1,0.3,0,0.3,0.1l0.9,1.4c0.1,0.1,0,0.3-0.1,0.3L341.5,797.6 C341.4,797.7,341.2,797.7,341.1,797.5z" data-step6="M476.4,1013.4L205,580.3c-0.1-0.1,0-0.3,0.1-0.3L1130.5,0.2c0.1-0.1,0.3,0,0.3,0.1l271.4,433.1c0.1,0.1,0,0.3-0.1,0.3 l-925.4,579.8C476.6,1013.6,476.5,1013.5,476.4,1013.4z">
		<svg height="100%" width="100%" preserveAspectRatio="none" viewBox="0 0 800 500">
			<title>SVG Modal background</title>
			<path id="cd-changing-path-1" d="M-59.9,540.5l-0.9-1.4c-0.1-0.1,0-0.3,0.1-0.3L864.8-41c0.1-0.1,0.3,0,0.3,0.1l0.9,1.4c0.1,0.1,0,0.3-0.1,0.3L-59.5,540.6 C-59.6,540.7-59.8,540.7-59.9,540.5z"/>
			<path id="cd-changing-path-2" d="M-465.1,287.5l-0.9-1.4c-0.1-0.1,0-0.3,0.1-0.3L459.5-294c0.1-0.1,0.3,0,0.3,0.1l0.9,1.4c0.1,0.1,0,0.3-0.1,0.3 l-925.4,579.8C-464.9,287.7-465,287.7-465.1,287.5z"/>
			<path id="cd-changing-path-3" d="M341.1,797.5l-0.9-1.4c-0.1-0.1,0-0.3,0.1-0.3L1265.8,216c0.1-0.1,0.3,0,0.3,0.1l0.9,1.4c0.1,0.1,0,0.3-0.1,0.3L341.5,797.6 C341.4,797.7,341.2,797.7,341.1,797.5z"/>
		</svg>
	</div>

	<div class="cd-modal-content">
		<!-- modal content here -->
	</div> <!-- cd-modal-content -->

	<a href="#0" class="modal-close">Close</a>
</div> <!-- cd-modal -->

<div class="cd-cover-layer"></div> <!-- .cd-cover-layer -->
An additional div.cd-cover-layer has been used to cover the main content when the modal window is fired (it is positioned between the modal window and the main content of the page).

Adding style

The .cd-modal window has, initially, visibility: hidden, height: 100% and width: 100% and is in fixed position. When user clicks the a#modal-trigger, the visibility of the modal window is changed to visible (using the .modal-is-visible class).
.cd-modal {
  position: fixed;
  z-index: 2;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  visibility: hidden;
  transition: visibility 0s 0.6s;
}
.cd-modal.modal-is-visible {
  visibility: visible;
  transition: visibility 0s 0s;
}
To create the modal background covering effect, we animate the 'd' attribute of the <path> elements inside the div.cd-svg-bg > svg (more in the Events handling section). Our first approach to creating the "masked" text effect consisted in using the SVG foreignObject to include the modal content into the SVG element. This way we could use the path elements as a reference to cut the text outside the animated background. However, we had several issues, mostly related to browsers compatibility. That's why we decided to use this simple trick instead: when the modal window is fired, a layer (.cd-cover-layer) becomes visible, right below the modal background, and, immediately after, the text becomes visible as well. The .cd-cover-layer and the text have the same color, this way only the text over the blue paths is visible during the animation. More in details: when a user clicks the a#modal-trigger, the .modal-is-visible class is added to the .cd-cover-layer and the .cd-modal. This class changes the .cd-cover-layer opacity from 0 to 1 and its visibility from hidden to visible, so that the .cd-cover-layer entirely covers the page main content.
.cd-cover-layer {
  position: fixed;
  z-index: 1;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  background-color: #f2f2f2;
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.3s 0.3s, visibility 0s 0.6s;
}
.cd-cover-layer.modal-is-visible {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.3s 0s, visibility 0s 0s;
}
As soon as the .cd-cover-layer opacity transition is over, the opacity of the .cd-modal-content is set to 1:
.cd-modal-content {
  color: #f2f2f2;
  opacity: 0;
  transform: translateY(50px);
  transition: opacity 0.3s 0s, transform 0.3s 0s;
}
.modal-is-visible .cd-modal-content {
  opacity: 1;
  transform: translateY(0);
  transition: opacity 0.3s 0.3s, transform 0.3s 0.3s;
}
Since the color of the .cd-modal-content is the same of the .cd-cover-layer background color, the only visible content will be the one over the blue svg background (which is still animating), while the one over the .cd-cover-layer won't be visible.

Events handling

To animate the modal background, we animated the 'd' attribute of the  3 <path> elements inside the svg. First, we defined the two steps of our animation, using the same process described in the Animated SVG Hero Slider article (Events handling section). Once defined the paths, we added to the .cd-svg-bg a data-stepn attribute (one for each step) equal to the 'd' attribute of the defined path (to easily retrieve it with JavaScript). We then used the animate() method provided by Snap.svg to animate the path element.
modalTrigger.on('click', function(event){ //modalTrigger =  $('a[data-type="cd-modal-trigger"]')
	event.preventDefault();
	$([modal.get(0), coverLayer.get(0)]).addClass('modal-is-visible'); //modal = $('.cd-modal'), coverLayer = $('.cd-cover-layer')
	animateModal(pathsArray, pathSteps, duration, 'open');
});

function animateModal(paths, pathSteps, duration, animationType) {
	var path1 = ( animationType == 'open' ) ? pathSteps[1] : pathSteps[0], // pathSteps[n] = $('.cd-svg-bg').data('step'+(n+1));
		path2 = ( animationType == 'open' ) ? pathSteps[3] : pathSteps[2],
		path3 = ( animationType == 'open' ) ? pathSteps[5] : pathSteps[4];
	paths[0].animate({'d': path1}, duration, firstCustomMinaAnimation); //paths[0] = Snap('#cd-changing-path-1')
	paths[1].animate({'d': path2}, duration, firstCustomMinaAnimation); //paths[1] = Snap('#cd-changing-path-2')
	paths[2].animate({'d': path3}, duration, firstCustomMinaAnimation); //paths[2] = Snap('#cd-changing-path-3')
}

Multi-Level Accordion Menu

$
0
0
multi-level-accordion-menu-featured A simple CSS accordion menu with support for sub level items. Today's resource is a handy accordion menu with support for groups/subitems. It works with CSS only, using the :checked pseudo-class selector on the checkboxes input elements. However we included a version with jQuery as well, in case you prefer a subtle animation compared to the instant default effect. Your call! The first user case I can think of for this resources is a "layer organizer". Think of Sublime Text sidebar, or Photoshop layer window. Anyway, I'm sure you'll find a use for this new snippet to store in your arsenal ;) Icons: Nucleoapp.com

Creating the structure

The HTML structure is pretty simple: the accordion is an unordered list. If a list item contains subitems, then we insert an input[type=checkbox] and its label. Also, we add the .has-children class to the list item. All "standard" list items contain just an anchor tag.
<ul class="cd-accordion-menu">
	<li class="has-children">
		<input type="checkbox" name ="group-1" id="group-1" checked>
		<label for="group-1">Group 1</label>

  		<ul>
  			<li class="has-children">
  				<input type="checkbox" name ="sub-group-1" id="sub-group-1">
				<label for="sub-group-1">Sub Group 1</label>

				<ul>
					<li><a href="#0">Image</a></li>
					<li><a href="#0">Image</a></li>
					<li><a href="#0">Image</a></li>
				</ul>
  			</li>
  			<li><a href="#0">Image</a></li>
			<li><a href="#0">Image</a></li>
  		</ul>
	</li>

	<li><a href="#0">Image</a></li>
	<li><a href="#0">Image</a></li>
</ul> <!-- cd-accordion-menu -->

Adding style

We use a smart (and quite standard nowadays) technique to detect the click and show sub content with CSS only: by including a checkbox input element, we can use the :checked pseudo-class and the adjacent sibling selector (div + div) to change the display mode of the sub <ul> element from "none" to "block". Step by step: first of all, we have to make sure that the checkbox input element covers the entire list item that contains subitems. Put in other words: we need to create a custom checkbox. So, firstly, you need to make sure that when you click on the label, the checkbox is checked/unchecked as well. This is achieved by using the "for" attribute inside the label (label "for" attribute = input "name" and "id" attributes. See html section above). This way you can simply hide the input element and work with the label instead.
.cd-accordion-menu input[type=checkbox] {
	/* hide native checkbox */
	position: absolute;
	opacity: 0;
}
.cd-accordion-menu label, .cd-accordion-menu a {
	position: relative;
	display: block;
	padding: 18px 18px 18px 64px;
	background: #4d5158;
	box-shadow: inset 0 -1px #555960;
	color: #ffffff;
	font-size: 1.6rem;
}
Now notice in the HTML structure that input, label and the unordered list (that we make visible on click) are siblings. By using the :checked pseudo-class, you can set the following process in motion: when the checkbox input is checked (click on label), then take the <ul> sibling element and change its display value from "none" to "block":
.cd-accordion-menu ul {
	/* by default hide all sub menus */
	display: none;
}

.cd-accordion-menu input[type=checkbox]:checked + label + ul,
.cd-accordion-menu input[type=checkbox]:checked + label:nth-of-type(n) + ul {
	/* use label:nth-of-type(n) to fix a bug on safari (<= 8.0.8) with multiple adjacent-sibling selectors*/
	/* show children when item is checked */
	display: block;
}
If you want to gently animate the opening phase, then include the .js file as well. Also remember to add the .animate class to the main .cd-accordion-menu element (this will animate the arrow rotation).

Animated Intro Section

$
0
0
animated-intro-section A collection of fancy text effects, to animate the tagline and action buttons of your website intro section. Animations in web design are often used to drive the user’s focus to a specific section. One section  you want to make sure to highlight is the main tagline, with the action buttons. A good use of typography and a wise choice of colors should do the trick. However we decided to spice things up a little by creating some text effects that you can easily apply to the intro section of your web projects.

Creating the structure

The HTML structure for each effect is pretty simple: a section.cd-intro is used as a container for the div.cd-intro-content which wraps the main tagline. The structure for the main tagline slightly differs from one effect to the other: for the bouncy effect, for example, we used an <h1> for the page title, a <p> tag as tagline, and a div.action-wrapper to wrap the action buttons:
<section class="cd-intro">
	<div class="cd-intro-content bouncy">
		<h1>Animated Intro Section</h1>
		<p>A collection of text effects for the intro section of your website</p>
		<div class="action-wrapper">
			<a href="#0" class="cd-btn main-action">Get started</a>
			<a href="#0" class="cd-btn">Learn More</a>
		</div>
	</div>
</section>
The .bouncy class added to the .cd-into-content is used to trigger the animation.

Adding style

By default, we hide the intro content by setting its opacity to zero, then we animate it using CSS Animations. For the bouncy effect, for example, we created 3 different animations for the <h1>, <p> and .cd-btn buttons:
.cd-intro-content h1,
.cd-intro-content p,
.cd-intro-content .cd-btn {
  opacity: 0;
  animation-delay: 0.3s;
  animation-fill-mode: forwards;
}

.bouncy.cd-intro-content h1 {
  animation-name: cd-bounce-right;
}

.bouncy.cd-intro-content p {
  animation-name: cd-bounce-left;
}

.bouncy.cd-intro-content h1,
.bouncy.cd-intro-content p {
  animation-duration: 0.6s;
}

.bouncy.cd-intro-content .cd-btn {
  animation-name: cd-bounce-rotate;
  animation-duration: 0.5s;
}

.bouncy.cd-intro-content .cd-btn.main-action {
  animation-delay: 0.4s;
}

@keyframes cd-bounce-right {
  0% {
    opacity: .2;
    transform: translateX(-200px);
  }
  60% {
    opacity: .7;
    transform: translateX(15px);
  }
  100% {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes cd-bounce-left {
  0% {
    opacity: .2;
    transform: translateX(200px);
  }
  60% {
    opacity: .7;
    transform: translateX(-15px);
  }
  100% {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes cd-bounce-rotate {
  0% {
    opacity: .2;
    transform: perspective(800px) rotateX(-80deg);
  }
  20% {
    opacity: 1;
  }
  60% {
    transform: perspective(800px) rotateX(20deg);
  }
  100% {
    opacity: 1;
    transform: perspective(800px) rotateX(0);
  }
}
Let's take a look at the video effect now: if you open the video.html file, you can see that an additional div.cd-bg-video-wrapper has been inserted; this element is used to wrap the background video (you won't see any <video> element inside the HTML because it's loaded using Javascript - more in the 'Events Handling' section). Besides, we inserted two svg elements (.svg-mask and .svg-mask-mobile) inside the <h1>: these svgs are used to create the title transparency effect (the first one when the device width is bigger than 768px, the second for the other devices). Basically, the idea is: we create an opaque rectangular <path> element but then we add a transparent area in the shape of the page title (in our demo, 'Video Effect'). The svg is then used as a layer to cover the entire .cd-intro-content: the transparent area of the svg lets you see what's below it (the background video). You can create a svg mask simply by using a vector graphic editor. We used Illustrator, where we created a rectangle and then removed the text using the pathfinder tool.
.cd-bg-video-wrapper {
  /* background cover video */
  position: absolute;
  z-index: 1;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: url(../assets/bg-img.jpg) no-repeat center center;
  background-size: cover;
}
.cd-bg-video-wrapper video {
  /* you won't see this element in the html, but it will be injected using js */
  display: block;
  position: absolute;
  left: 50%;
  top: 50%;
  bottom: auto;
  right: auto;
  transform: translateX(-50%) translateY(-50%);
  min-height: 100%;
  min-width: 100%;
  max-width: none;
  height: auto;
  width: auto;
}

.video.cd-intro-content svg {
  position: absolute;
  z-index: 2;
  /* center the svg inside its parent */
  left: 50%;
  top: 50%;
  bottom: auto;
  right: auto;
  transform: translateX(-50%) translateY(-50%);
  opacity: 0.8;
}
.video.cd-intro-content svg.svg-mask {
  /* this is the svg mask used on desktop version */
  display: none;
}
@media only screen and (min-width: 768px) {
  .video.cd-intro-content svg.svg-mask-mobile {
    display: none;
  }
  .video.cd-intro-content svg.svg-mask {
    display: block;
  }
}

Events handling

These intro effects have been created using CSS only. We used jQuery for the video effect only to load the background video if the device width is bigger than 768px. A data-video has been added to the  div.cd-bg-video-wrapper to retrieve the video url.

Stretchy Navigation

$
0
0
stretchy-navigation A rounded navigation trigger that stretches on click/tap to reveal the navigation items. While surfing some Dribbble shots, we came across this nice shopping list concept by Hila Peleg, which inspired today’s resource. We decided to apply a similar idea to a stretching navigation, and create 3 different user cases where this snippet would be useful: 1) fixed navigation, 2) add content button and 3) edit content button. Icons: Nucleoapp.com

Creating the structure

The HTML structure is pretty basic: a nav.cd-stretchy-nav is used to wrap an unordered list (containing the navigation items) and an a.cd-nav-trigger (for the menu icon). An additional span.stretchy-nav-bg element is used to create the stretchy background.
<nav class="cd-stretchy-nav">
	<a class="cd-nav-trigger" href="#0">
		Menu
		<span aria-hidden="true"></span>
	</a>

	<ul>
		<li><a href="#0" class="active"><span>Home</span></a></li>
		<li><a href="#0"><span>Portfolio</span></a></li>
		<!-- other list items here -->
	</ul>

	<span aria-hidden="true" class="stretchy-nav-bg"></span>
</nav>

Adding style

We created the .cd-stretchy-nav class to define the main style for the stretchy navigation. We then used two additional classes, .add-content and .edit-content, to customise the toolbars for adding and editing content respectively. The basic idea of the animation is: we assign to the span.stretchy-nav-bg a fixed height and width (the same of the a.cd-nav-trigger); when the navigation is open, we use the .nav-is-visible class to animate its height (or width, for the .add-content toolbar) to create the stretching effect while revealing the navigation list items.
.cd-stretchy-nav {
  position: fixed;
  z-index: 2;
  top: 40px;
  right: 5%;
}
.cd-stretchy-nav .stretchy-nav-bg {
  /* this is the stretching navigation background */
  position: absolute;
  z-index: 1;
  top: 0;
  right: 0;
  width: 60px;
  height: 60px;
  border-radius: 30px;
  background: #9acd91;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
  transition: height 0.2s, box-shadow 0.2s;
}
.cd-stretchy-nav.nav-is-visible .stretchy-nav-bg {
  height: 100%;
  box-shadow: 0 6px 30px rgba(0, 0, 0, 0.2);
}
For the navigation items, we defined 2 different CSS Animations: the scaleIn for the item icons and the slideIn for the item labels; the animation-delay property is then used to animate different children at different moments.
.cd-stretchy-nav ul {
  position: relative;
  z-index: 2;
  visibility: hidden;
  transition: visibility 0.3s;
}
.cd-stretchy-nav ul a {
  position: relative;
}
.cd-stretchy-nav ul a::after {
  /* navigation item icons */
  content: '';
  position: absolute;
  height: 16px;
  width: 16px;
  transform: translateY(-50%) scale(0);
  opacity: .6;
  background: url(../img/cd-sprite-1.svg) no-repeat 0 0;
}
.cd-stretchy-nav ul span {
  /* navigation item labels */
  display: block;
  opacity: 0;
  transform: translateX(-25px);
}

.cd-stretchy-nav.nav-is-visible ul {
  visibility: visible;
}
.cd-stretchy-nav.nav-is-visible ul a::after {
  /* navigation item icons */
  transform: translateY(-50%) scale(1);
  animation: scaleIn 0.15s backwards;
}
.cd-stretchy-nav.nav-is-visible ul span {
  opacity: 1;
  transform: translateX(0);
  animation: slideIn 0.15s backwards;
}

.cd-stretchy-nav.nav-is-visible ul li:first-of-type a::after,
.cd-stretchy-nav.nav-is-visible ul li:first-of-type span {
  animation-delay: 0.05s;
}
/* animation delay for other children here ...*/

@keyframes scaleIn {
  from {
    transform: translateY(-50%) scale(0);
  }
  to {
    transform: translateY(-50%) scale(1);
  }
}

@keyframes slideIn {
  from {
    opacity: 0;
    transform: translateX(-25px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}
For the toolbars: when the navigation is open we only display the item icons (using the scaleIn animation), while the item labels are shown when hovering over the navigation (using CSS Transitions). For the editing toolbar, for example, we have:
.cd-stretchy-nav.edit-content ul span {
  position: absolute;
  top: 0;
  right: 35px;
  height: 30px;
  line-height: 30px;
  opacity: 0;
  visibility: hidden;
  background-color: rgba(0, 0, 0, 0.55);
  transition: opacity 0.2s, visibility 0.2s;
}
.cd-stretchy-nav.edit-content ul span::after {
  /* triangle below the tooltip */
  content: '';
  position: absolute;
  left: 100%;
  top: 50%;
  bottom: auto;
  transform: translateY(-50%);
  height: 0;
  width: 0;
  border: 4px solid transparent;
  border-left-color: rgba(0, 0, 0, 0.55);
}

.no-touch .cd-stretchy-nav.edit-content.nav-is-visible ul a:hover span {
  opacity: 1;
  visibility: visible;
}

Events handling

We used jQuery to listen to the click event on the a.cd-nav-trigger, and add/remove the .nav-is-visible class from the nav.cd-stretchy-nav.

Horizontal Timeline

$
0
0
horizontal-timeline An easy to customize, horizontal timeline powered by CSS and jQuery. Our vertical timeline is so far one of the most popular resources on CodyHouse. Many of you asked us to include a horizontal timeline as well. Here it is! Building a horizontal timeline was a bit tricky, because you can’t rely on the vertical (more intuitive) scrolling behaviour. We decided to separate timeline and events, with the first one working like a slider, while the second one occupying the full width and showing a single event at a time.

Creating the structure

The HTML structure is composed by two main ordered lists: the first one containing the timeline dates and the second one the events. An additional ul.cd-timeline-navigation has been used for the navigation arrows, and a span.filling-line to create the filling effect when a new event is selected.
<section class="cd-horizontal-timeline">
	<div class="timeline">
		<div class="events-wrapper">
			<div class="events">
				<ol>
					<li><a href="#0" data-date="16/01/2014" class="selected">16 Jan</a></li>
					<li><a href="#0" data-date="28/02/2014">28 Feb</a></li>
					<!-- other dates here -->
				</ol>

				<span class="filling-line" aria-hidden="true"></span>
			</div> <!-- .events -->
		</div> <!-- .events-wrapper -->

		<ul class="cd-timeline-navigation">
			<li><a href="#0" class="prev inactive">Prev</a></li>
			<li><a href="#0" class="next">Next</a></li>
		</ul> <!-- .cd-timeline-navigation -->
	</div> <!-- .timeline -->

	<div class="events-content">
		<ol>
			<li class="selected" data-date="16/01/2014">
				<h2>Horizontal Timeline</h2>
				<em>January 16th, 2014</em>
				<p>
					Lorem ipsum dolor sit amet, consectetur adipisicing elit. Illum praesentium officia, fugit recusandae ipsa, quia velit nulla adipisci? Consequuntur aspernatur at, eaque hic repellendus sit dicta consequatur quae, ut harum ipsam molestias maxime non nisi reiciendis eligendi! Doloremque quia pariatur harum ea amet quibusdam quisquam, quae, temporibus dolores porro doloribus.
				</p>
			</li>

			<li data-date="28/02/2014">
				<!-- event description here -->
			</li>

			<!-- other descriptions here -->
		</ol>
	</div> <!-- .events-content -->
</section>

Adding style & Guidelines

Let's start from the events style: all the items are translated to the left, outside the viewport (translateX(-100%)); the .selected class is added to the visible event to move it back into the viewport (translateX(0)). 4 classes have been used to create the slider animation: the .enter-right/.enter-left classes added to the selected event item entering the viewport from right/left, and the .leave-right/.leave-left classes added to the event item moving to the right/left while leaving the viewport. These classes are used to apply two different CSS animations: cd-enter-right (for the .enter-right and .leave-left class) and cd-enter-left (for the .enter-left and .leave-right class).
.cd-horizontal-timeline .events-content {
  position: relative;
}
.cd-horizontal-timeline .events-content li {
  position: absolute;
  z-index: 1;
  width: 100%;
  left: 0;
  top: 0;
  transform: translateX(-100%);
  opacity: 0;
  animation-duration: 0.4s;
  animation-timing-function: ease-in-out;
}
.cd-horizontal-timeline .events-content li.selected {
  /* visible event content */
  position: relative;
  z-index: 2;
  opacity: 1;
  transform: translateX(0);
}
.cd-horizontal-timeline .events-content li.enter-right,
.cd-horizontal-timeline .events-content li.leave-right {
  animation-name: cd-enter-right;
}
.cd-horizontal-timeline .events-content li.enter-left,
.cd-horizontal-timeline .events-content li.leave-left {
  animation-name: cd-enter-left;
}
.cd-horizontal-timeline .events-content li.leave-right,
.cd-horizontal-timeline .events-content li.leave-left {
  animation-direction: reverse;
}
@keyframes cd-enter-right {
  0% {
    opacity: 0;
    transform: translateX(100%);
  }
  100% {
    opacity: 1;
    transform: translateX(0%);
  }
}
@keyframes cd-enter-left {
  0% {
    opacity: 0;
    transform: translateX(-100%);
  }
  100% {
    opacity: 1;
    transform: translateX(0%);
  }
}
About the timeline: the position of each date along the timeline is set using jQuery. Dates are not equally distributed along the timeline, but the distance between a date and the next one is proportional to the difference between these dates. First of all, in the main.js file, we set a minimum distance between two consecutive dates, using the eventsMinDistance variable; in our case, we set eventsMinDistance = 60 (so the minimum distance will be 60px). Then we evaluate all the differences between a date and the following one; to do that we use the data-date attribute added to each date. The minimum difference is then used as a reference to evaluate the distances between two consecutive dates. For example, let's suppose the minimum found difference is 5 days; that means that the distance, along the timeline, between two dates separated by a lapse of 5days will  be 60px, while the one between two events separated by a lapse of 10 days will be 120px. About the date format: we used the date format DD/MM/YYYY, but you can also add time, if you need to take that into account. There are 3 different date formats you can use:
  • DD/MM/YYYY -> day only;
  • DD/MM/YYYYTHH:MM -> if you need to consider time too (e.g., 02/10/2015T19:45);
  • HH:MM -> time only (for events happening within the same day).
Last note: the data-date used for a timeline date has to be set to the respective event too (list items inside the .events-content element). This way, when a user selects a new date along the timeline, the corresponding event can be shown.

Reading Progress Indicator

$
0
0
reading-progress-indicator A widget containing a list of suggested articles, with a reading progress indicator powered by SVG, CSS and jQuery. Today’s resource was inspired by a widget found on The Daily Beast: a list of related articles, enriched by a filling effect to indicate the reading progress. We created something similar, although we used SVG to animate the stroke property of a circle element. Note that the url changes according to the article in focus, in case the user wants to share a specific article as opposed to the whole page. Since such a widget is not a fundamental element of the page, but more of a subtle enrichment, we decided to hide it on smaller devices.

Creating the structure

The HTML structure is composed by <article> elements for the article contents, and an <aside> element wrapping the list of suggested articles.
<div class="cd-articles">
	<article>
		<header>
			<img src="img/img-1.png" alt="article image">
			<h1>20 Star Wars Secrets Revealed: From Leia’s ‘Cocaine Nail’ to the Ronald Reagan Connection</h1>
		</header>

		<p>
			Lorem ipsum dolor sit amet, consectetur adipisicing elit. Perferendis maxime id, sunt, eum sed blanditiis aliquid! Minus assumenda tempore perspiciatis, numquam est aliquam, quis molestias enim consequuntur suscipit similique cumque ut natus facilis laboriosam quidem, nesciunt quasi doloribus tenetur. Quas doloremque suscipit, molestias odit, et quasi? Quas hic numquam, vitae?
		</p>
		<!-- additional content here -->
	</article>

	<article>
		<!-- article content here -->
	</article>

	<!-- additional articles here -->

	<aside class="cd-read-more">
		<ul>
			<li>
				<a href="index.html">
					<em>20 Star Wars Secrets Revealed</em>
					<b>by J. Morrison</b>
					<svg x="0px" y="0px" width="36px" height="36px" viewBox="0 0 36 36"><circle fill="none" stroke="#2a76e8" stroke-width="2" cx="18" cy="18" r="16" stroke-dasharray="100 100" stroke-dashoffset="100" transform="rotate(-90 18 18)"></circle></svg>
				</a>
			</li>

			<!-- additional links to articles -->
		</ul>
	</aside> <!-- .cd-read-more -->
</div> <!-- .cd-articles -->

Adding style

The <aside> element is visible only on big devices (viewport width bigger than 1100px): it has an absolute position and is placed in the top-right corner of the .cd-articles element; the class .fixed is then used to change its position to fixed so that it's always accessible while the user scrolls through the articles.
@media only screen and (min-width: 1100px) {
  .cd-articles {
    position: relative;
    width: 970px;
    padding-right: 320px;
  }
}

.cd-read-more {
  /* hide on mobile */
  display: none;
}
@media only screen and (min-width: 1100px) {
  .cd-read-more {
    display: block;
    width: 290px;
    position: absolute;
    top: 3em;
    right: 0;
  }
  .cd-read-more.fixed {
    position: fixed;
    right: calc(50% - 485px);
  }
}
To create the progress effect, we used the two svg attributes stroke-dasharray and stroke-dashoffset. Imagining the circle as a dashed line, the stroke-dasharray lets you specify dashes and gaps length, while the stroke-dashoffset lets you change where the dasharray starts. We initially set stroke-dasharray="100 100" and stroke-dashoffset="100" (where 100 is the svg circle circumference). This way, the dash and gap are both equal to the circle circumference, and since the stroke-dashoffset is equal to the circle circumference too, only the gap (transparent) is visible. To create the progress effect, we change the stroke-dashoffset from 100 to 0 (more in the Events Handling section).

Events handling

On big devices (viewport width bigger than 1100px) we bind the updateArticle() and updateSidebarPosition() functions to the window scroll events: the first one checks which article the user is reading and updates the corresponding svg stroke-dashoffset attribute to show the progress, while the second function updates the sidebar position attribute (using the .fixed class ) according to the window scroll top value. Finally, the changeUrl() function is used to update the page url according to the article being read.
function updateArticle() {
	var scrollTop = $(window).scrollTop();

	articles.each(function(){ //articles = $('.cd-articles').children('article');
		var article = $(this),
			articleSidebarLink = articleSidebarLinks.eq(article.index()).children('a'); //articleSidebarLinks = $('.cd-read-more').find('li')

		if( articleTop > scrollTop) { //articleTop = $(this).offset().top
			articleSidebarLink.removeClass('read reading');
		} else if( scrollTop >= articleTop && articleTop + articleHeight > scrollTop) { //articleHeight = $(this).outerHeight()
			var dashoffsetValue = svgCircleLength*( 1 - (scrollTop - articleTop)/articleHeight); //svgCircleLength = 100
			articleSidebarLink.addClass('reading').removeClass('read').find('circle').attr({ 'stroke-dashoffset': dashoffsetValue });
			changeUrl(articleSidebarLink.attr('href'));
		} else {
			articleSidebarLink.removeClass('reading').addClass('read');
		}
	});
}

function updateSidebarPosition() {
	var scrollTop = $(window).scrollTop();

	if( scrollTop < articlesWrapperTop) { //$('.cd-articles').offset().top
		aside.removeClass('fixed').attr('style', ''); //aside = $('.cd-read-more')
	} else if( scrollTop >= articlesWrapperTop && scrollTop < articlesWrapperTop + articlesWrapperHeight - windowHeight) { // articlesWrapperHeight = $('.cd-articles').outerHeight()
		aside.addClass('fixed').attr('style', '');
	} else {
		if( aside.hasClass('fixed') ) aside.removeClass('fixed').css('top', articlesWrapperHeight + articlePaddingTop - windowHeight + 'px');//articlePaddingTop = Number($('.cd-articles').children('article').eq(1).css('padding-top').replace('px', ''))
	}
}

Pointy Slider

$
0
0
pointy-slider A slideshow with sliding-in panels that unveil new, fixed background images. Today’s resource is a simple, responsive slider, with a sharp design and an interesting motion effect: with each new slide item, a sliding-in block of content covers the old one, and unveils a new image. Inspiration: shft.run Images: unsplash.com

Creating the structure

The HTML structure is composed by two main elements: a ul.cd-slider for the slides, and a ol.cd-slider-navigation for the slider navigation; both are wrapped inside a div.cd-slider-wrapper.
<div class="cd-slider-wrapper">
	<ul class="cd-slider">
		<li class="is-visible">
			<div class="cd-half-block image"></div>

			<div class="cd-half-block content">
				<div>
					<h2>Slide Number 1</h2>
					<p>
						<!-- content here -->
					</p>
				</div>
			</div>
		</li> <!-- .cd-half-block.content -->

		<li>
			<!-- item content here -->
		</li>

		<!-- addition list items here -->
	</ul> <!-- .cd-slider -->

	<!-- The ol.cd-slider-navigation element is created using jQuery and inserted here-->
</div> <!-- .cd-slider-wrapper -->
Note that the ol.cd-slider-navigation element is not directly inserted in the HTML but created using jQuery.

Adding style

On small devices (viewport width smaller than 900px), the slider structure is pretty straightforward: the .cd-slider element has a relative position while its children <li> have an absolute position, with a top and left of zero. All the list items are translated to the right, outside the viewport (translateX(100%)); the .is-visible class is added to the visible one to move it back into the viewport (translateX(0)).
.cd-slider {
  position: relative;
  height: 100%;
  overflow: hidden;
}
.cd-slider li {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  transform: translateX(100%);
  transition: transform 0.6s;
}
.cd-slider li.is-visible {
  transform: translateX(0);
}
On bigger devices, the list items are moved back inside the viewport (translateX(0)), while their two children elements, .cd-half-block.content and .cd-half-block.image, are translated to the right (translateX(200%) and translateX(100%) respectively). This way, both elements are outside the viewport, overlapping. When the .is-visible class is added to the selected list item, the two .cd-half-block elements are moved back inside the viewport (translateX(0)). We used CSS3 Transitions to animate both elements: for the .cd-half-block.content we set a transition-duration of 0.6s and a transition-delay of 0s, while for the .cd-half-block.image we set a transition-duration of 0s and a transition-delay of 0.3s. This way, when the .cd-half-block.content has translated of half the total translation value (100%), the .cd-half-block.image is moved back inside the viewport (translateX(0)) instantaneously (transition-duration: 0s). This creates the unveiling image effect. Here is a quick animation that explains the logic behind the blocks animation (.gif created using After Effects): pointy-blocks-animation
@media only screen and (min-width: 900px) {
  .cd-slider li {
    transform: translateX(0);
  }
  .cd-slider .cd-half-block {
    height: 100%;
    width: 50%;
    float: right;
  }
  .cd-slider .cd-half-block.content {
    transform: translateX(200%);
    transition: transform 0.6s 0s ease-in-out;
  }
  .cd-slider .cd-half-block.image {
    transform: translateX(100%);
    transition: transform 0s 0.3s;
  }
  .cd-slider li.is-visible .cd-half-block.content,
  .cd-slider li.is-visible .cd-half-block.image {
    transform: translateX(0%);
  }
  .cd-slider li.is-visible .cd-half-block.content {
    transition: transform 0.6s 0s ease-in-out;
  }
}
One thing to note: we set the .cd-half-block.image transition-delay to be equal to half the .cd-half-block.content transition-duration. This is because we used ease-in-out as timing-function, which assures that after half the transition-duration (in our case .3s), the .cd-half-block.content has actually moved of half the total translation value.

Events handling

We used jQuery to create and insert into the DOM the slider navigation.
var sliderPagination = createSliderPagination(sliderContainer); // sliderContainer = $('.cd-slider-wrapper')

function createSliderPagination(container){
	var wrapper = $('<ol class="cd-slider-navigation"></ol>');
	container.children('.cd-slider').find('li').each(function(index){
		var dotWrapper = (index == 0) ? $('<li class="selected"></li>') : $('<li></li>'),
			dot = $('<a href="#0"></a>').appendTo(dotWrapper);
		dotWrapper.appendTo(wrapper);
		var dotText = ( index+1 < 10 ) ? '0'+ (index+1) : index+1;
		dot.text(dotText);
	});
	wrapper.appendTo(container);
	return wrapper.children('li');
}
Besides, we used jQuery to implement a basic slider functionality (touch swipe and slider navigation).

Advanced Search Form

$
0
0
advanced-search A search form with advanced filtering options and quick link suggestions. Getting the search experience right is never an easy task. The starting point is always the search form, which, in most cases, consists only of an input field plus a submit button. The search results page can be tricky to design, in particular if you have different content categories. For big websites and online stores, what is crucial though is to try to anticipate a user’s move. We have to take into account that often our users are not clear about where to find specific information on our website. In those cases they tend to turn to the search form. Providing filtering options and quick links upfront is a way to narrow the search experience to what the user is really interested in, as well as a way to build simpler, more focused search result pages. Here is a quick animation that shows our advanced search form in action: advanced-search-animation

Creating the structure

The HTML structure is composed by three main elements: a <header> element, wrapping the main navigation, a div.cd-main-search for the search form and a main.cd-main-content for the page main content.
<header class="cd-main-header animate-search">
	<div class="cd-logo"><a href="#0"><img src="img/cd-logo.svg" alt="Logo"></a></div>

	<nav class="cd-main-nav-wrapper">
		<a href="#search" class="cd-search-trigger cd-text-replace">Search</a>

		<ul class="cd-main-nav">
			<li><a href="#0">Products</a></li>
			<!-- additional navigation items -->
		</ul>
	</nav>

	<a href="#0" class="cd-nav-trigger cd-text-replace">Menu<span></span></a>
</header>

<main class="cd-main-content">
	<!-- your content here -->
</main>

<div id="search" class="cd-main-search">
	<form>
		<input type="search" placeholder="Search...">

		<div class="cd-select">
			<span>in</span>
			<select name="select-category">
				<option value="all-categories">all Categories</option>
				<!-- additional options here -->
			</select>
			<span class="selected-value">all Categories</span>
		</div>
	</form>

	<div class="cd-search-suggestions">
		<div class="news">
			<h3>News</h3>
			<ul>
				<li>
					<a class="image-wrapper" href="#0"><img src="img/placeholder.png" alt="News image"></a>
					<h4><a class="cd-nowrap" href="#0">Lorem ipsum dolor sit amet, consectetur adipisicing elit.</a></h4>
					<time datetime="2016-01-12">Feb 03, 2016</time>
				</li>

				<!-- additional news here -->
			</ul>
		</div> <!-- .news -->

		<div class="quick-links">
			<h3>Quick Links</h3>
			<ul>
				<li><a href="#0">Find a store</a></li>
				<!-- additional quick links here -->
			</ul>
		</div>
	</div> <!-- .cd-search-suggestions -->

	<a href="#0" class="close cd-text-replace">Close Form</a>
</div> <!-- .cd-main-search -->

Adding style

On small devices (viewport width smaller than 1024px), the main navigation and the search form are on the right side, hidden by default; when a user clicks the menu icon, the <main> and <header> elements translate to the left (nav-is-visible class is applied) to reveal the navigation.
.cd-main-header, .cd-main-content {
  position: relative;
  transition: transform 0.3s;
}
.cd-main-header.nav-is-visible, .cd-main-content.nav-is-visible {
  transform: translateX(-260px);
}
On bigger devices, the search form is on top of the main navigation, hidden by default. When a user clicks the .cd-search-trigger element, the .is-visible class is used to reveal the form.
@media only screen and (min-width: 1024px) {
  .cd-main-search {
    position: absolute;
    z-index: 2;
    top: 0;
    left: 0;
    height: 100%;
    width: 100%;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.3s, visibility 0.3s;
  }
  .cd-main-search.is-visible {
    /* search form open */
    opacity: 1;
    visibility: visible;
  }
}
To trigger the search form animation, we use the .animate-search class added to the <header> element. This class triggers two different CSS3 Animations: cd-slide-in (for the search form) and cd-3d-rotation (for the suggestions dropdown).
@media only screen and (min-width: 1024px) {
  .animate-search .cd-main-search.is-visible {
    /* trigger search form animation if <header> has the .animate-search class */
    animation: cd-slide-in 0.3s;
  }
  .animate-search .is-visible .cd-search-suggestions {
    /* trigger the dropdown animation if <header> has the .animate-search class */
    transform-origin: center top;
    animation: cd-3d-rotation 0.5s 0.3s;
    animation-fill-mode: backwards;
  }
}
@keyframes cd-slide-in {
  0% {
    transform: translateY(-100%);
  }
  100% {
    transform: translateY(0);
  }
}

@keyframes cd-3d-rotation {
  0% {
    transform: perspective(1000px) rotateX(-90deg);
  }
  100% {
    transform: perspective(1000px) translateY(0);
  }
}
If you prefer a basic fade-in effect (rather than animating the search form), you can remove the .animate-search class from the <header> element. About the category selection: to make sure the div.cd-select width changes according to the option the user chooses, the <select> element is in absolute position (so it doesn't take space), while a span.selected-value is used to show the option selected (its text is changed  when the user selects a new option using jQuery).
@media only screen and (min-width: 1024px) {
  .cd-main-search .cd-select {
    position: absolute;
    right: 0;
    overflow: hidden;
  }
  .cd-main-search select {
    /* the <select> element is not visible - it is covered by the .selected-value element */
    position: absolute;
    right: 0;
    opacity: 0;
    color: transparent;
  }
  .cd-main-search .selected-value {
    color: #ffffff;
    pointer-events: none;
  }
  .cd-main-search select, .cd-main-search .selected-value {
    padding: 0.5em 1.7em 0.5em .3em;
    font-size: 1.4rem;
    border-radius: 3px;
  }
}

Events handling

In the starting HTML structure, the navigation is inside the <header>. On small devices, we wanted the navigation to be on the side, hidden by default, and it was easier for us to have it outside the <header>. So we use jQuery to do that. We do the same for the div.cd-main-search: by default, it's outside the main navigation, while on small devices we move it inside the nav.cd-main-nav-wrapper element.
var navigationWrapper = $('.cd-main-nav-wrapper'),
	navigation = navigationWrapper.children('.cd-main-nav'),
	searchForm = $('.cd-main-search'),
	navigationTrigger = $('.cd-nav-trigger'),
	mainHeader = $('.cd-main-header');

function moveNavigation(){
	var screenSize = checkWindowWidth(); //returns 'mobile' or 'desktop'
    if ( screenSize == 'desktop' && (navigationTrigger.siblings('.cd-main-search').length == 0) ) {
    	//desktop screen - insert navigation and search form inside <header>
    	searchForm.detach().insertBefore(navigationTrigger);
		navigationWrapper.detach().insertBefore(searchForm).find('.cd-serch-wrapper').remove();
	} else if( screenSize == 'mobile' && !(mainHeader.children('.cd-main-nav-wrapper').length == 0)) {
		//mobile screen - move navigation and search form after .cd-main-content element
		navigationWrapper.detach().insertAfter('.cd-main-content');
		var newListItem = $('<li class="cd-serch-wrapper"></li>');
		searchForm.detach().appendTo(newListItem);
		newListItem.appendTo(navigation);
	}
}
Besides, we used jQuery to detect click events and add/remove classes accordingly and to change the span.selected-value text when user selects a different option from the <select> dropdown.

Products Comparison Table

$
0
0
product-comparison-table A responsive table to compare and filter through multiple products. If you’re developing an online store with plenty of products, in all likelihood you’ve been asked to work on this feature: the comparison table. The standard approach, that works in most cases, is to use a simple HTML table element. If you have 6+ products to compare, though, things can get tricky, particularly when you try to make the whole thing responsive. With today’s resource we wanted to provide a time-saver comparison table, specifically designed for big online stores. Our inspiration is the comparison tool we found on the beautifully designed Sony UK website. In terms of UX though, instead of letting users remove products from the list, we let them select, and filter, the ones they want to compare.

Creating the structure

The HTML structure is composed of a section.cd-products-comparison-table wrapping a <header> and a div.cd-products-table. The <header> contains the action buttons (filter and reset), while the div.cd-products-table is used to wrap the div.features (product features list) and the div.cd-products-wrapper. The latter contains an unordered list (ul.cd-products-columns) for the product list items.
<section class="cd-products-comparison-table">
	<header>
		<h2>Compare Models</h2>

		<div class="actions">
			<a href="#0" class="reset">Reset</a>
			<a href="#0" class="filter">Filter</a>
		</div>
	</header>

	<div class="cd-products-table">
		<div class="features">
			<div class="top-info">Models</div>
			<ul class="cd-features-list">
				<li>Price</li>
				<li>Customer Rating</li>
				<li>Resolution</li>
				<!-- other features here -->
			</ul>
		</div> <!-- .features -->

		<div class="cd-products-wrapper">
			<ul class="cd-products-columns">
				<li class="product">
					<div class="top-info">
						<div class="check"></div>
						<img src="../img/product.png" alt="product image">
						<h3>Sumsung Series 6 J6300</h3>
					</div> <!-- .top-info -->

					<ul class="cd-features-list">
						<li>$600</li>
						<li class="rate"><span>5/5</span></li>
						<li>1080p</li>
						<!-- other values here -->
					</ul>
				</li> <!-- .product -->

				<li class="product">
					<!-- product content here -->
				</li> <!-- .product -->

				<!-- other products here -->
			</ul> <!-- .cd-products-columns -->
		</div> <!-- .cd-products-wrapper -->

		<ul class="cd-table-navigation">
			<li><a href="#0" class="prev inactive">Prev</a></li>
			<li><a href="#0" class="next">Next</a></li>
		</ul>
	</div> <!-- .cd-products-table -->
</section> <!-- .cd-products-comparison-table -->

Adding style

The .cd-products-wrapper has a width of 100% and overflow-x of auto; the .cd-products-columns, instead, has a width equal to the sum of all columns widths and is scrollable (because of its parent overflow property). The div.features has an absolute position and is fixed on the left side of the viewport.
.cd-products-wrapper {
  overflow-x: auto;
  /* this fixes the buggy scrolling on webkit browsers - mobile devices only - when overflow property is applied */
  -webkit-overflow-scrolling: touch;
}

.cd-products-table .features {
  /* fixed left column - product properties list */
  position: absolute;
  z-index: 1;
  top: 0;
  left: 0;
  width: 120px;
}

.cd-products-columns {
  /* products list wrapper */
  width: 1200px; /* single column width * products number */
  margin-left: 120px; /* .features width */
}
On big devices (viewport width greater than 1170px), the .top-fixed class is added to the .cd-products-table when user scrolls down to fix the products top information (product name and image):
@media only screen and (min-width: 1170px) {
  .cd-products-table.top-fixed .cd-products-columns > li {
    padding-top: 160px;
  }

  .cd-products-table.top-fixed .top-info {
    height: 160px;
    position: fixed;
    top: 0;
  }

  .cd-products-table.top-fixed .top-info h3 {
    transform: translateY(-116px);
  }

  .cd-products-table.top-fixed .top-info img {
    transform: translateY(-62px) scale(0.4);
  }

}

Events handling

To implement the products table, we created a productsTable object and used the bindEvents function to attach event handlers to the proper elements:
function productsTable( element ) {
	this.element = element;
	this.table = this.element.children('.cd-products-table');
	this.productsWrapper = this.table.children('.cd-products-wrapper');
	this.tableColumns = this.productsWrapper.children('.cd-products-columns');
	this.products = this.tableColumns.children('.product');
	//additional properties here
	// bind table events
	this.bindEvents();
}

productsTable.prototype.bindEvents = function() {
	var self = this;

	self.productsWrapper.on('scroll', function(){
		//detect scroll left inside products table
	});

	self.products.on('click', '.top-info', function(){
		//add/remove .selected class to products
	});

	self.filterBtn.on('click', function(event){
		//filter products
	});
	//reset product selection
	self.resetBtn.on('click', function(event){
		//reset products visibility
	});

	this.navigation.on('click', 'a', function(event){
		//scroll inside products table - left/right arrows
	});
}

var comparisonTables = [];
$('.cd-products-comparison-table').each(function(){
	//create a productsTable object for each .cd-products-comparison-table
	comparisonTables.push(new productsTable($(this)));
});
You may have noticed that we added an event listener to the scroll event of the .cd-products-wrapper; when the .top-fixed class is added to the .cd-products-table, the .top-info elements are in fixed position, so they don't scroll with the .cd-products-columns. The updateLeftScrolling() function is used to horizontally translate these elements while the user scrolls inside the .cd-products-wrapper.
productsTable.prototype.updateLeftScrolling = function() {
	var scrollLeft = this.productsWrapper.scrollLeft();

	if( this.table.hasClass('top-fixed') && checkMQ() == 'desktop') setTranformX(this.productsTopInfo, '-'+scrollLeft);
}

Ink Transition Effect

$
0
0
ink-transition-effect An ink bleed transition effect, powered by CSS animations. I recently came across a couple of websites using ink bleeds as transition effects. A great example is the Sevenhills website. At first I thought they were using a HTML canvas powered technique (for allowing transparency), then I checked the source code and found out they weren’t using a video, but a PNG image sprite. By using a PNG sprite and the steps() timing function in CSS, we can create video effects and use them as transitions! In our resource, we used this technique to fire a modal window, but you can use it to transition between two different pages as well. The process to create these effects is simple, let me break it down for you: First, you need a video with a filling effect and a transparent area. Then you need to export this video as a PNG sequence. We used After Effects to export the sequence (make sure to export the alpha channel as well). ae-01 Since our video is composed of 25 frames, the assets exported are 25 PNG images. Just to give you more info about the composition settings, we created a 640x360px video with a duration of 1 second and a frame rate equal to 25. ae-02 Finally the tedious part: you need to create the PNG sprite, by creating a new image that includes all frames on the same row. We did this manually using Photoshop, and combined all frames into a single 16000x360 pixels image. png-sequence-preview In order to turn the sequence into a video, we just need to translate the PNG sprite, and use the steps() function to define the number of frames. Do you want to learn more about CSS transforms and animations? Check out our course ;) Now let’s jump into the code!

Creating the structure

The HTML structure is composed of 3 main elements: a main.cd-main-content for the page main content, a div.cd-modal for the modal window and a div.cd-transition-layer for the transition layer.
<main class="cd-main-content">
	<div class="center">
		<h1>Ink Transition Effect</h1>
		<a href="#0" class="cd-btn cd-modal-trigger">Start Effect</a>
	</div>
</main> <!-- .cd-main-content -->

<div class="cd-modal">
	<div class="modal-content">
		<h1>My Modal Content</h1>

		<p>
			Lorem ipsum dolor sit amet, consectetur adipisicing elit.
			Ad modi repellendus, optio eveniet eligendi molestiae?
			Fugiat, temporibus!
		</p>
	</div> <!-- .modal-content -->

	<a href="#0" class="modal-close">Close</a>
</div> <!-- .cd-modal -->

<div class="cd-transition-layer">
	<div class="bg-layer"></div>
</div> <!-- .cd-transition-layer -->

Adding style

The .cd-modal window has, initially, visibility: hidden, height: 100% and width: 100% and is in fixed position. When a user clicks the a.cd-modal-trigger, the visibility of the modal window is changed to visible and its opacity to 1 (using the .visible class).
.cd-modal {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 3;
  height: 100%;
  width: 100%;
  opacity: 0;
  visibility: hidden;
}
.cd-modal.visible {
  opacity: 1;
  visibility: visible;
}
The div.cd-transition-layer element is used to create the transition ink effect: it has visibility: hidden, height: 100% and width: 100% and is in fixed position.
.cd-transition-layer {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 2;
  height: 100%;
  width: 100%;
  opacity: 0;
  visibility: hidden;
  overflow: hidden;
}
Its child element div.bg-layer has the ink.png sprite as background-image, a background-size: 100%,  height: 100% and width: 2500% (the ink.png sprite is composed of 25 frames); its left/top/translate values are set so that, initially, the first frame of the ink.png sprite is centered inside the div.cd-transition-layer:
.cd-transition-layer .bg-layer {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translateY(-50%) translateX(-2%);
  height: 100%;
  /* our sprite is composed of 25 frames */
  width: 2500%;
  background: url(../img/ink.png) no-repeat 0 0;
  background-size: 100% 100%;
}
Note: to center an element inside its parent, you would use:
position: absolute;
left: 50%;
top: 50%;
transform: translateY(-50%) translateX(-50%);
In our case, though, we want to center the first frame of the ink.png sprite, and since div.bg-layer width is 25 times the one of its parent, we use a translateX(-(50/25)%). To create the ink animation, we change the translate value of the div.bg-layer; we defined the cd-sequence keyframes rule:
@keyframes cd-sequence {
  0% {
    transform: translateY(-50%) translateX(-2%);
  }
  100% {
    transform: translateY(-50%) translateX(-98%);
  }
}
This way, at the end of the animation, the last frame of the ink.png sprite is centered inside the div.cd-transition-layer element. Note: since we have 25 frames, to show the last one you need to translate the .bg-layer of -100% * (25 - 1) = -96%; but then, to center it inside its parent, you need to add the additional -2%. When a user clicks the a.cd-modal-trigger, the .visible class is added to the .cd-transition-layer to show it, while the .opening class is used to trigger the ink animation:
.cd-transition-layer.visible {
  opacity: 1;
  visibility: visible;
}
.cd-transition-layer.opening .bg-layer {
  animation: cd-sprite 0.8s steps(24);
  animation-fill-mode: forwards;
}
Note that we used the steps() function: that's because we don't want the translate value to change continuously, but rather change through fixed steps, in order to show one frame at a time; the number of steps used is equal to our frames less one.

Events handling

We used jQuery to add/remove classes when user clicks the a.cd-modal-trigger or .modal-close to open/close the modal window. Besides, we change the .bg-layer dimensions in order not to modify the png frames aspect ratio. In the style.css file, we set .bg-layer height and width so that each frame has height and width equal to the ones of the viewport. Viewport and frames could have a different aspect ratio though and that could distort the single frame. The setLayerDimensions() function has been used to prevent this from happening:
var frameProportion = 1.78, //png frame aspect ratio
	frames = 25, //number of png frames
	resize = false;

//set transitionBackground dimentions
setLayerDimensions();
$(window).on('resize', function(){
	if( !resize ) {
		resize = true;
		(!window.requestAnimationFrame) ? setTimeout(setLayerDimensions, 300) : window.requestAnimationFrame(setLayerDimensions);
	}
});

function setLayerDimensions() {
	var windowWidth = $(window).width(),
		windowHeight = $(window).height(),
		layerHeight, layerWidth;

	if( windowWidth/windowHeight > frameProportion ) {
		layerWidth = windowWidth;
		layerHeight = layerWidth/frameProportion;
	} else {
		layerHeight = windowHeight;
		layerWidth = layerHeight*frameProportion;
	}

	transitionBackground.css({
		'width': layerWidth*frames+'px',
		'height': layerHeight+'px',
	});

	resize = false;
}

360 Degrees Product Viewer

$
0
0
360 Degrees Product Viewer A simple, interactive resource that can be used to provide a virtual tour of your product. In e-commerce design, one of the main goals is to fill the gap between product and user. This is particularly relevant for high-priced goods. Hence, the importance to integrate interactive tools, to provide the user a way to “virtually experience” the product. Today’s resource is a simple, interactive resource that can be used to show a virtual tour of the product. The idea behind the snippet is to use an image sprite and link the dragging to a specific frame of that image. You can use it to show the exterior of a technology gadget (or a car, like in our demo!), or, in general, to create fancy product animations. Photo credits: Alfa Romeo.

Creating the structure

The HTML structure is composed of two main elements: a figure.product-viewer for the image sprite and the product preview image, and a div.cd-product-viewer-handle for the viewer handle.
<div class="cd-product-viewer-wrapper" data-frame="16" data-friction="0.33">
	<div>
		<figure class="product-viewer">
			<img src="img/product-loading.jpg" alt="Product Preview">
			<div class="product-sprite" data-image="img/product.png"></div>
		</figure> <!-- .product-viewer -->

		<div class="cd-product-viewer-handle">
			<span class="fill"></span>
			<span class="handle">Handle</span>
		</div>
	</div> <!-- .cd-product-viewer-handle -->
</div> <!-- .cd-product-viewer-wrapper -->
The data-frame attribute of the div.cd-product-viewer-wrapper specifies the number of frames the image sprite is composed of, while the data-friction specifies the friction while dragging on the image (it has to be greater than zero).

Adding style

The <img> element is visible only at the beginning, while the image sprite is still loading, and is used to give the proper dimensions to the figure.product-viewer element. As for the div.product-sprite, it has an absolute position, a height of 100% and width of 1600% (our image sprite is composed of 16 frames) and is hidden by default. The .loaded class is then used to show the div.product-sprite once the image sprite has been loaded:
.cd-product-viewer-wrapper .product-viewer {
  position: relative;
  overflow: hidden;
}
.cd-product-viewer-wrapper img {
  /* this is the image visible before the image sprite is loaded */
  display: block;
  position: relative;
  z-index: 1;
}
.cd-product-viewer-wrapper .product-sprite {
  position: absolute;
  z-index: 2;
  top: 0;
  left: 0;
  height: 100%;
  /* our image sprite is composed of 16 frames */
  width: 1600%;
  background: url(../img/product.png) no-repeat center center;
  background-size: 100%;
  opacity: 0;
  transition: opacity 0.3s;
}
.cd-product-viewer-wrapper.loaded .product-sprite {
  /* image sprite has been loaded */
  opacity: 1;
}
When the user drags the span.handle or the product image, we change the div.product-sprite translateX value to show a different image frame (using JavaScript). Note: the frames composing your image sprite should have the same aspect ratio of the product preview image. The handle loading effect is achieved by changing the scaleX value of the span.fill element (using JavaScript); once the image sprite has been loaded, the span.fill is hidden and the span.handle is shown:
.cd-product-viewer-handle {
  position: relative;
  z-index: 2;
  width: 60%;
  max-width: 300px;
  height: 4px;
  background: #4d4d4d;
}
.cd-product-viewer-handle .fill {
  /* this is used to create the loading fill effect */
  position: absolute;
  z-index: 1;
  left: 0;
  top: 0;
  height: 100%;
  width: 100%;
  border-radius: inherit;
  background: #b54240;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.5s;
}
.loaded .cd-product-viewer-handle .fill {
  /* image sprite has been loaded */
  opacity: 0;
}
.cd-product-viewer-handle .handle {
  position: absolute;
  z-index: 2;
  display: inline-block;
  height: 44px;
  width: 44px;
  left: 0;
  top: -20px;
  background: #b54240 url(../img/cd-arrows.svg) no-repeat center center;
  border-radius: 50%;
  transform: translateX(-50%) scale(0);
}
.loaded .cd-product-viewer-handle .handle {
  /* image sprite has been loaded */
  transform: translateX(-50%) scale(1);
  animation: cd-bounce 0.3s 0.3s;
  animation-fill-mode: both;
}
@keyframes cd-bounce {
  0% {
    transform: translateX(-50%) scale(0);
  }
  60% {
    transform: translateX(-50%) scale(1.1);
  }
  100% {
    transform: translateX(-50%) scale(1);
  }
}

Events handling

To implement the product viewer, we created a productViewer object and used the loadFrames method to check whether the image sprite has been loaded:
var productViewer = function(element) {
	this.element = element;
	this.handleContainer = this.element.find('.cd-product-viewer-handle');
	this.handleFill = this.handleContainer.children('.fill');
	//...
	this.frames = this.element.data('frame');
	//increase this value to increase the friction while dragging on the image - it has to be bigger than zero
	this.friction = this.element.data('friction');
	this.visibleFrame = 0;
	this.loaded = false;
	//...
	this.loadFrames();
}

productViewer.prototype.loadFrames = function() {
	var self = this,
		imageUrl = this.slideShow.data('image');
	//you need this to check if the image sprite has been loaded
	$('<img/>').attr('src', imageUrl).load(function() {
		self.loaded = true;
	});

	this.loading('0.5'); //triggers loading animation
}

var productToursWrapper = $('.cd-product-viewer-wrapper');
productToursWrapper.each(function(){
	new productViewer($(this));
});
Once the image sprite has been loaded, we attach an event handler for the mousedown/mousemove/mouseup events to the proper elements:
if( self.loaded ){
	//sprite image has been loaded
	self.element.addClass('loaded');
	self.dragImage();
	self.dragHandle();
	//..
} else {
	//...
}
For this effect to work on touch devices, we used the vmousedown/vmousemove/vmouseup events provided by the jQuery mobile framework.

Animated Transition Effects

$
0
0
Animated Transition Effects A library of animated transition effects, powered by CSS Animations. A few weeks ago we published a tutorial about how to create an Ink Transition effect using a PNG sprite and the steps() CSS timing function. That resource has since become one of the most popular here on CodyHouse, therefore we decided to team up with talented motion designer Gabriele Mellera to create a small library of transition effects! If you want to learn how to create your own transition effects, here is our thorough tutorial: Ink Transition Effect Tutorial

How to use the transition effects

We created a separate html file for each effect. Note the class applied to the <body>, that we used in CSS to target the specific effect.
<!doctype html>
<html lang="en" class="no-js">
<head>
	<!-- ... -->

	<title>Cartoon Transition Effect | CodyHouse</title>
</head>
<body class="cartoon-transition">
<main class="cd-main-content">
	<!-- ... -->
</main>

<div class="cd-modal" id="modal-1">
	<!-- ... -->
</div>

<div class="cd-transition-layer" data-frame="25">
	<div class="bg-layer"></div>
</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script>
	if( !window.jQuery ) document.write('<script src="js/jquery-2.2.1-min.js"><\/script>');
</script>
<script src="js/main.js"></script> <!-- Resource jQuery -->
</body>
</html>
The CSS file is organized in different sections. For a transition to work properly you need to include the style shared by all effects, the custom effect style, and the keyframes to control the animation.
/* --------------------------------

Shared style

-------------------------------- */

.cd-btn {
  display: inline-block;
  padding: 1.6em 2.4em;
  font-size: 1.4rem;
  letter-spacing: .15em;
  font-weight: 700;
  text-transform: uppercase;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
  transition: box-shadow .3s;
  /*...*/
}

/* --------------------------------

Scrub Effect - Custom effect style

-------------------------------- */

.scrub-transition {
  font-family: "PT Sans", sans-serif;
  color: #2c1a32;
  /*...*/
}

/* --------------------------------

Animations - remember to check the animation name to copy the correct keyframes

-------------------------------- */

@keyframes cd-sequence {
  0% {
    /* translateX(-2%) is used to horizontally center the first frame inside the viewport */
    transform: translateY(-50%) translateX(-2%);
  }
  100% {
    /* translateX(-98%) (2% + 96) is used to horizontally center the last frame inside the viewport  */
    transform: translateY(-50%) translateX(-98%);
  }
}
If you want to change the color of the transitions, all you need to do is importing the PNG image sprites into a graphic tool, and change the color of the filled area. For example, in Photoshop you can use layer styles to apply a color overlay. Once you've edited the image, simply save it as PNG. If you're concerned about the size, TinyPNG is a great tool to compress PNG images. Change image color
Viewing all 26 articles
Browse latest View live