How to create horizontal carousel in JavaScript? - javascript

Goal: To create a carousel effect when switching between items laid out in a list. Consider the following HTML structure:
<div class="container">
<ul class="gallery">
<li class="slide">
<!-- Some content -->
</li>
<li class="slide">
<!-- Some content -->
</li>
<!-- Some more items -->
</ul>
</div>
Initially, the list gallery should be centered inside the container, with each list item slide stacked on top of each other. After populating the slides with relevant data, the first slide should be made active, while the second slide be scaled a bit smaller and less opaque (among other styling that shows that this slide is not active, but in queue). All the other slides should be hidden.
Now, clicking on any item (slide) - except for the active one - should trigger the carousel effect, which looks similar to this implementation by GreenSock (The difference is that, first their implementation is dependent on scrolling through mouse-wheel, whereas, I want the effect to take place on clicking an item. Also, their implementation requires the use of third-party library GSAP and ScrollTrigger, but I do not want to use either of them - only plain DOM manipulation. Additionally, they have infinite scroll but I do not want to circle back to the other end when list is finished in either end.)

To create a 3-item carousel effect, we define five possible states for our slide:
lhidden (hidden on the leftmost side)
lqueue (in queue on the left side)
active (the currently active slide)
rqueue (in queue on the right side)
rhidden (hidden on the rightmost side)
The styling for these five states makes use of CSS opacity, z-index, and transform properties.
.slide.active {
opacity: 1;
z-index: 2;
transform: translate(0px) scale(1);
}
.slide.lqueue {
opacity: 0.64;
z-index: 1;
transform: translate(-100%) scale(0.64);
}
.slide.rqueue {
opacity: 0.64;
z-index: 1;
transform: translate(100%) scale(0.64);
}
.slide.lhidden {
opacity: 0;
z-index: auto;
transform: translate(-160%) scale(0);
}
.slide.rhidden {
opacity: 0;
z-index: auto;
transform: translate(160%) scale(0);
}
To place the list gallery in center of the container, we use flex display on container and set its align-center and justify-content to center. Then, to make so that each item in the list is stacked on top of each other in the same place, we set relative position on the list, and absolute position on each item, with top margin equal to 0.
.container {
display: flex;
align-items: center;
justify-content: center;
}
..gallery {
position: relative;
width: 400px; /* Can be anything */
height: 650px; /* Can be anything */
list-style: none;
}
.slide {
position: absolute;
top: 0;
width: 100%;
height: 100%;
}
In the JavaScript, we iterate over each slide and set add rhidden to their class list. After which, we manually set the first slide to have active and the second slide to have rqueue class respectively. Then, we attach an event listener to the click event on each slide, passing its index as argument, so that we can manipulate its immediate siblings to achieve the carousel effect.
function initializeCarousel(){
const slides = document.querySelectorAll(".slide");
for (let index = 0; index < slides.length; index++) {
const slide = slides[index];
slide.classList.add("rhidden");
slide.addEventListener("click", () => {
activateCarousel(index);
});
}
slides[0].classList = "slide active";
slides[1].classList = "slide rqueue";
}
We can only click on three types of slides since we cannot click on hidden ones:
active
lqueue
rqueue
If we clicked on active slide, we need to do nothing and simply return.
If we clicked on either lqueue or rqueue slide, we set itself to be active, and make its surrounding siblings have queue and hidden states based on its index difference from the clicked slide.
function activateCarousel(index) {
const slides = document.querySelectorAll(".slide");
const slide = slides[index];
if (slide.classList.contains("active")) {
return;
}
slide.classList = "slide active";
if (slides[index - 2] != undefined) {
slides[index - 2].classList = "slide lhidden";
}
if (slides[index - 1] != undefined) {
slides[index - 1].classList = "slide lqueue";
}
if (slides[index + 1] != undefined) {
slides[index + 1].classList = "slide rqueue";
}
if (slides[index + 2] != undefined) {
slides[index + 2].classList = "slide rhidden";
}
}
A complete implementation should look like the following snippet.
function activateCarousel(index) {
const slides = document.querySelectorAll(".slide");
const slide = slides[index];
if (slide.classList.contains("active")) {
return;
}
slide.classList = "slide active";
if (slides[index - 2] != undefined) {
slides[index - 2].classList = "slide lhidden";
}
if (slides[index - 1] != undefined) {
slides[index - 1].classList = "slide lqueue";
}
if (slides[index + 1] != undefined) {
slides[index + 1].classList = "slide rqueue";
}
if (slides[index + 2] != undefined) {
slides[index + 2].classList = "slide rhidden";
}
}
function initializeCarousel() {
const slides = document.querySelectorAll(".slide");
for (let index = 0; index < slides.length; index++) {
const slide = slides[index];
slide.classList.add("rhidden");
slide.addEventListener("click", () => {
activateCarousel(index);
});
}
slides[0].classList = "slide active";
slides[1].classList = "slide rqueue";
}
initializeCarousel();
/* Root structure */
:root {
--color-primary: #1a1a1d;
--color-secondary: #955d80;
--color-tertiary: #d3b6bf;
}
*,
*::before,
*::after {
box-sizing: border-box;
padding: 0;
margin: 0;
}
ul {
list-style: none;
}
.container {
height: 100vh;
background-image: linear-gradient(180deg, #ce0240, #a80135);
display: flex;
align-items: center;
justify-content: center;
}
/* Gallery list layout */
.gallery {
position: relative;
width: 400px;
height: 650px;
list-style: none;
}
/* Individual item a.k.a "slide" structure */
.slide {
position: absolute;
top: 0;
width: 100%;
height: 100%;
background-image: linear-gradient(180deg, #ffe9e3, #ffe9e3);
border-radius: 25px;
padding: 50px;
display: flex;
gap: 0.5rem;
flex-direction: column;
align-items: center;
transition: all 0.3s;
}
/* Slide states */
.slide.active {
opacity: 1;
z-index: 2;
transform: translate(0px) scale(1);
}
.slide.lqueue {
opacity: 0.64;
z-index: 1;
transform: translate(-100%) scale(0.64);
}
.slide.rqueue {
opacity: 0.64;
z-index: 1;
transform: translate(100%) scale(0.64);
}
.slide.lhidden {
opacity: 0;
z-index: auto;
transform: translate(-160%) scale(0);
}
.slide.rhidden {
opacity: 0;
z-index: auto;
transform: translate(160%) scale(0);
}
.slide.lqueue *,
.slide.rqueue *,
.slide.lhidden *,
.slide.rhidden * {
pointer-events: none;
}
.slide.lqueue *::selection,
.slide.rqueue *::selection,
.slide.lhidden *::selection,
.slide.rhidden *::selection {
background-color: transparent;
}
/* Slide specifics */
.slide--picture {
width: 300px;
height: 320px;
object-position: top;
object-fit: cover;
border-radius: 25px;
box-shadow: -10px 10px 60px #ce0240;
margin-bottom: 30px;
}
.slide--name,
.slide--description {
width: 100%;
text-align: left;
font-weight: bold;
}
.slide--name {
color: var(--color-primary);
font-size: 1.6rem;
}
.slide--description {
font-size: 1rem;
color: var(--color-secondary);
}
<main class="container">
<ul class="gallery">
<li class="slide">
<img class="slide--picture" src="https://d31wcbk3iidrjq.cloudfront.net/l0TNFUosa_avatar-Ex0lN8A5U.jpg?h=320&w=300&q=100" alt="Slide picture">
<h2 class="slide--name">Puff Johnson</h2>
<p class="slide--description">NCAA Basketball - North Carolina Tar Heels</p>
</li>
<li class="slide">
<img class="slide--picture" src="https://d31wcbk3iidrjq.cloudfront.net/JbSCP9pbj_avatar-A3Pby19td.jpg?h=320&w=300&q=100" alt="Slide picture">
<h2 class="slide--name">Maddie Poppe</h2>
<p class="slide--description">American Idol Season 16 Winner</p>
</li>
<li class="slide">
<img class="slide--picture" src="https://d31wcbk3iidrjq.cloudfront.net/Sa_09kTuP_avatar-76TOucMti.jpg?h=320&w=300&q=100" alt="Slide picture">
<h2 class="slide--name">Justin Roberts</h2>
<p class="slide--description">Ring Announcer & MC - AEW</p>
</li>
<li class="slide">
<img class="slide--picture" src="https://d31wcbk3iidrjq.cloudfront.net/t8EJJ9Ef4M_avatar-5xB9jXzKl.jpg?h=320&w=300&q=100" alt="Slide picture">
<h2 class="slide--name">Brodie That Dood</h2>
<p class="slide--description">Viral Star - Brodie The Goldendoodle</p>
</li>
<li class="slide">
<img class="slide--picture" src="https://d31wcbk3iidrjq.cloudfront.net/IPFAWngd3_avatar-_XExw5Daa.jpg?h=320&w=300&q=100" alt="Slide picture">
<h2 class="slide--name">Tony Vitello</h2>
<p class="slide--description">Tennessee Baseball Coach</p>
</li>
<li class="slide">
<img class="slide--picture" src="https://d31wcbk3iidrjq.cloudfront.net/hl_Vh7TFN_avatar-Y12cyyBbB.jpg?h=320&w=300&q=100" alt="Slide picture">
<h2 class="slide--name">Omar Narvaez</h2>
<p class="slide--description">MLB - Milwaukee Brewers</p>
</li>
<li class="slide">
<img class="slide--picture" src="https://d31wcbk3iidrjq.cloudfront.net/1xY4Ue6wb_avatar-aR2of-zCB.jpg?h=320&w=300&q=100" alt="Slide picture">
<h2 class="slide--name">Jordan Schlansky</h2>
<p class="slide--description">Associate Producer - The Conan O'Brien Show</p>
</li>
<li class="slide">
<img class="slide--picture" src="https://d31wcbk3iidrjq.cloudfront.net/Zs7_MjEtl_93Kxr22tk.png?h=320&w=300&q=100" alt="Slide picture">
<h2 class="slide--name">Colin Mochrie</h2>
<p class="slide--description">Comedian - Whose Line is it Anyway?</p>
</li>
<li class="slide">
<img class="slide--picture" src="https://d31wcbk3iidrjq.cloudfront.net/GrFxbkTTT_PBhuEqlck.jpg?h=320&w=300&q=100" alt="Slide picture">
<h2 class="slide--name">Tommy Chong</h2>
<p class="slide--description">Comedian - Musician - Actor - Writer</p>
</li>
<li class="slide">
<img class="slide--picture" src="https://d31wcbk3iidrjq.cloudfront.net/QQ-agNUb8_27456_001_002_0073_R.JPG?h=320&w=300&q=100" alt="Slide picture">
<h2 class="slide--name">James Murray</h2>
<p class="slide--description">TruTV - Impractical Jokers</p>
</li>
<li class="slide">
<img class="slide--picture" src="https://d31wcbk3iidrjq.cloudfront.net/gxtdQlFH2_avatar-snpKtIVyV.png?h=320&w=300&q=100" alt="Slide picture">
<h2 class="slide--name">Fortune Feimster</h2>
<p class="slide--description">Actress - Comedian</p>
</li>
<li class="slide">
<img class="slide--picture" src="https://d31wcbk3iidrjq.cloudfront.net/IH6BNRNN1_5F746EBF-BB49-43F6-9EC7-51B4FF831859.jpeg?h=320&w=300&q=100" alt="Slide picture">
<h2 class="slide--name">Andrew Dice Clay</h2>
<p class="slide--description">Comedian</p>
</li>
<li class="slide">
<img class="slide--picture" src="https://d31wcbk3iidrjq.cloudfront.net/X85ZZzwEE_IMG_09552.JPG?h=320&w=300&q=100" alt="Slide picture">
<h2 class="slide--name">Anthony Anderson</h2>
<p class="slide--description">Actor - Black-ish</p>
</li>
<li class="slide">
<img class="slide--picture" src="https://d31wcbk3iidrjq.cloudfront.net/MdckbEzZy_35105081995_5d36db665a_k.jpg?h=320&w=300&q=100" alt="Slide picture">
<h2 class="slide--name">Fiona the Hippo</h2>
<p class="slide--description">Animals - Cincinnati Zoo</p>
</li>
<li class="slide">
<img class="slide--picture" src="https://d31wcbk3iidrjq.cloudfront.net/8VF6SrNzw_avatar-jowRSkmuT.jpg?h=320&w=300&q=100" alt="Slide picture">
<h2 class="slide--name">Susie Essman</h2>
<p class="slide--description">HBO - Curb Your Enthusiasm</p>
</li>
</ul>
</main>

Related

How can I make it so only the tab area loads instead of the page jumping to the top after clicking on tab?

As the title states, I'm making a tabbed section to switch content upon click which works fine, how can I make it so upon clicking a new tab it has a smooth transition to the content as well as prevent jumping to the top of the page every time I click a tab?
I've tried adding the function which prevents it for links but this isn't a link so that doesn't seem to be working.
HTML
<section class="featured-books">
<div class="featured-books-title"><h2>Featured Books</h2></div>
<ul class="tabs">
<li data-tab-target="#featured" class="active tab">Featured</li>
<li data-tab-target="#on-sale" class="tab">On Sale</li>
<li data-tab-target="#most-viewed" class="tab">Most Viewed</li>
</ul>
<div id="featured" data-tab-content class="active">
<div class="featured-tab">
<img src="./images/12-rules.jpg">
<img src="./images/7-habits.jpg">
<img src="./images/art-of-war.jpg">
<img src="./images/boundaries.jpg">
<img src="./images/unlimited-memory.jpg">
<img src="./images/meaning-of-marriage.jpg">
<img src="./images/meditations.jpg">
<img src="./images/peaceful-parents.jpg">
<img src="./images/plant-paradox.jpg">
<img src="./images/spirit-filled-life.jpg">
<img src="./images/javascript-definitive-guide.jpg">
<img src="./images/atomic-habits.jpg">
</div>
</div>
<div id="on-sale" data-tab-content>
</div>
<div id="most-viewed" data-tab-content>
</div>
</section>
CSS
.featured-books h1 {
display: flex;
justify-content: center;
}
[data-tab-content] {
display: none;
}
.active[data-tab-content] {
display: block;
}
.tabs {
display: flex;
justify-content: center;
list-style-type: none;
margin: 0;
padding-bottom: 60px;
padding-top: 16px;
}
.tab {
border-radius: 20px;
cursor: pointer;
padding: 10px;
}
.tab.active {
background-color: #CCC;
}
.tab:hover {
background-color: #aaa;
}
/**------FEATURED TAB CONTENT------*/
.featured-tab {
position: absolute;
justify-content: center;
align-items: center;
margin-top: 10px;
width: 100vw;
display: grid;
grid-template-columns: repeat(auto-fill,minmax(300px,300px));
column-gap: 3px;
row-gap: 40px;
}
.featured-tab img {
width: 180px;
height: auto;
object-fit: cover;
object-position: center;
}
JavaScript
const tabContents = document.querySelectorAll('[data-tab-content]')
tabs.forEach(tab => {
tab.addEventListener('click', () => {
const target = document.querySelector(tab.dataset.tabTarget)
tabContents.forEach(tabContent => {
tabContent.classList.remove('active')
})
tabs.forEach(tab => {
tab.classList.remove('active')
})
tab.classList.add('active')
target.classList.add('active')
})
})
Here is a simple example using a opacity transition but you can use height, width or transform if you would like. I use aria-attributes to keep track of things like which article is open and if the information in the article should be picked up by screen readers. The two most important CSS classes are show and hide. These control the opacity and when the transition takes place. Show has a slight delay so it waits for the one being hidden to get out of the way. As far as the JavaScript.
Select all the buttons that have popups.
Create a event listener to handle the click.
Select the controlled article and all the articles.
Check if the controlled article is currently hidden.
If it is hide all the artiles.
Change all the buttons aria-expanded attributes to false.
Set the aria-expanded attribute on the clicked button to true.
Set aria-hidden class on the controlled article to false.
Remove the hide class and add the show class to the controlled article.
const buttons = document.querySelectorAll("[aria-haspopup=true]")
const handleClick = (event) => {
const controls = event.target.getAttribute("aria-controls"),
controlled = document.getElementById(controls),
articles = document.querySelectorAll("article");
if (controlled.getAttribute("aria-hidden") === "true") {
articles.forEach(article => {
article.setAttribute("aria-hidden", "true");
article.classList.add("hide");
article.classList.remove("show");
})
buttons.forEach(button => button.setAttribute("aria-expanded", "false"))
event.target.setAttribute("aria-expanded", "true");
controlled.setAttribute("aria-hidden", "false");
controlled.classList.remove("hide");
controlled.classList.add("show");
}
}
buttons.forEach(button => {
button.addEventListener("click", handleClick);
})
ul {
list-style: none;
margin: 0;
padding: 0;
display: flex;
}
li {
margin-right: 10px;
}
article {
height: calc(100vh - 50px);
width: 100vw;
position: absolute;
top: 50px;
left: 0;
}
#feature {
background-color: red;
}
#sale {
background-color: green;
}
#view {
background-color: blue;
}
.show {
opacity: 1;
transition: opacity .2s ease-in-out .2s;
}
.hide {
opacity: 0;
transition: opacity .2s ease-in-out;
}
button[aria-expanded=true] {
background-color: #cceeff;
}
<ul>
<li>
<button aria-haspopup="true" aria-expanded="true" aria-controls="feature">Featured</button>
</li>
<li>
<button aria-haspopup="true" aria-expanded="false" aria-controls="sale">On Sale</button>
</li>
<li>
<button aria-haspopup="true" aria-expanded="false" aria-controls="view">Most Viewed</button>
</li>
</ul>
<article class="show" id="feature" aria-hidden="false">
<h1>Featured</h1>
</article>
<article class="hide" id="sale" aria-hidden="true">
<h1>On Sale</h1>
</article>
<article class="hide" id="view" aria-hidden="true">
<h1>Most Viewed</h1>
</article>

Javascript image slider not working properly

I'm trying to create an image slider with controls "Next" and "Previous". Next should slide the image left using a negative margin-left property so as to reveal the second image. All the list elements holding individual images are set to display: inline-block so each list element can stand next to each other instead of stacking.
However, I found out that when the first image slides left it still reveals a little out of it while showing the second image, on and on and on like that, everything slides but never fully. the distance they slide is equal to the width of the image.
Also, when I get to the last image and click on next it should go back to the first image, the problem is that it displays each image along the way to the first image.
window.onload = function () {
var nextBtn = document.getElementsByClassName("nextBtn")[0],
prevBtn = document.getElementsByClassName("prevBtn")[0];
var i = 0;
var imgList = document.querySelectorAll(".slide");
var slideLength = imgList.length;
var lastchild = imgList[slideLength - 1];
nextBtn.addEventListener("click", Next, false);
prevBtn.addEventListener("click", Previous, false);
function Next() {
console.log(slideLength)
imgList[i].style.marginLeft = "-600px";
if (imgList[i].classList.contains("active")) {
imgList[i].classList.remove("active");
}
if (imgList[i] !== lastchild) {
i++;
}
else if (imgList[i] === lastchild) {
i = 0;
for (var j = 0; j < slideLength; j++) {
imgList[j].style.marginLeft = "0";
}
}
imgList[i].classList.add("active");
}
function Previous(e) {
console.log(i);
if (i !== 0) {
imgList[i - 1].style.marginLeft = "0";
i--;
console.log(i);
}
else {
console.log(i);
}
}
}
ul{
width: 100%;
height: 350px;
border: solid 3px white;
margin:100px auto;
overflow: hidden;
}
li{
display:inline-block;
position: relative;
transition: all 1s cubic-bezier(1,-0.01, 0, 1.13);
list-style: none;
}
li img{
width:600px;
height:350px
}
.slide h2{
position: absolute;
bottom:80px;
text-align: center;
margin: 0 auto;
left: 250px;
color: #fff;
font-size: 4em;
font-weight: 900;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div class="container">
<ul class="slide-wrapper">
<li class="slide active">
<img src="http://placehold.it/350x150" alt="">
<h2>1</h2>
</li>
<li class="slide">
<img src="http://placehold.it/350x150" alt="">
<h2>2</h2>
</li>
<li class="slide">
<img src="http://placehold.it/350x150" alt="">
<h2>3</h2>
</li>
<li class="slide">
<img src="http://placehold.it/350x150" alt="">
<h2>4</h2>
</li>
<li class="slide">
<img src="http://placehold.it/350x150" alt="">
<h2>5</h2>
</li>
</ul>
</div>
<!--<div class="test">
</div>-->
<button class="nextBtn">Next</button>
<button class="prevBtn">Previous</button>
How can I make this work well strictly with vanilla javascript? Here is the link to the jsfiddle . However, it doesn't seem to work at all there.
Reference : https://jsfiddle.net/a2bk4bwu/3/
Replace your CSS with lines with the for ul & li
ul{
width: 100%;
height: 350px;
border: solid 3px white;
margin:100px auto;
overflow: hidden;
padding-left: 0;
font-size: 0px;
}
li{
font-size : 20px;
display:inline-block;
position: relative;
transition: all 1s cubic-bezier(1,-0.01, 0, 1.13);
list-style: none;
}
Things to note :
'Ul' was taking extra padding by default {webkit-padding-start: 40px}
"display : inline-block" items are dependent on "white-space". So give "0px" to the parent element to remove that white space between slides.
These will fix your CSS issues.

slidetoggle in pure Javascript

As you might see I have fixed a kind of text box that will pop up when someone is hovering over that image, but honestly I want a slide-up effect that gone up slowly. Must be completely in pure JavaScript (no jQuery please!). Anyone knows how I can do that.
function show(myText) {
var elements = document.getElementsByClassName(myText)
for(var i = 0; i < elements.length; i++){
elements[i].style.visibility = "visible";
}
}
function hide(myText) {
var elements = document.getElementsByClassName(myText)
for(var i = 0; i < elements.length; i++){
elements[i].style.visibility = "hidden";
}
}
.text1 {
position: relative;
bottom: 28px;
text-align: center;
background-color: grey;
width: 100%;
height: 10%;
font-size: 20px;
color: white;
opacity: 0.7;
display: block;
visibility: hidden;
}
.text2 {
position: relative;
bottom: 28px;
text-align: center;
background-color: grey;
width: 100%;
height: 10%;
font-size: 20px;
color: white;
opacity: 0.7;
display: block;
visibility: hidden;
}
<div class="row">
<div class="col-md-6 col-sm-12">
<div class="tumb-wrapper">
<a href="http://www.bbc.com" target="_blank" class="image" onmouseover="show('text1')" onmouseout="hide('text1')">
<img src="https://i.vimeocdn.com/portrait/8070603_300x300" class="project" alt="print-screen"/>
<div class="text1">AAA</div>
</a>
</div>
</div>
<div class="col-md-6 col-sm-12">
<div class="tumb-wrapper">
<a href="http://www.cnn.com" target="_blank" class="image" onmouseover="show('text2')" onmouseout="hide('text2')">
<img src="https://lh6.ggpht.com/mSKQgjFfPzrjqrG_d33TQZsDecOoVRF-jPKaMDoGIpMLLT1Q09ABicrXdQH6AZpLERY=w300" class="project" alt="print-screen"/>
<div class="text2">BBB</div>
</a>
</div>
</div>
</div>
Here is a version of it that's totally javascript free, just using CSS. I'm going to edit this soon with a slight javascript addition (this current version requires you to have a fixed size).
.caption {
height: 250px;
width: 355px;
overflow: hidden;
}
.caption-image {
height: 100%;
}
.caption-text {
color: white;
padding: 10px;
background: rgba(0, 0, 0, 0.4);
transition: transform 400ms ease;
}
.caption-image:hover + .caption-text,
.caption-text:hover {
transform: translateY(-100%);
}
<div class="caption">
<img class="caption-image" src="http://faron.eu/wp-content/uploads/2013/05/Cheese.jpg" />
<div class="caption-text">Some words about how cheesy it is to use a picture of cheese for this example!</div>
</div>
<div class="caption">
<img class="caption-image" src="https://top5ofanything.com/uploads/2015/05/Tomatoes.jpg" />
<div class="caption-text">There's nothing witty to say about a tomato, maybe some you say I say stuff. But honstly I can't think of anything...</div>
</div>
Version with JS sizing:
Basically the same idea, but when the page is loading it sets certain styles so the images can be what ever size you like.
var captionSel = document.querySelectorAll('.caption');
for (let i = 0; i < captionSel.length; i++) {
let image = captionSel[i].querySelector(":scope > .caption-image");
let text = captionSel[i].querySelector(":scope > .caption-text");
text.style.width = image.clientWidth - 20 + "px";
captionSel[i].style.height = image.clientHeight + "px";
}
.caption {
overflow: hidden;
}
.caption-text {
color: white;
padding: 10px;
background: rgba(0, 0, 0, 0.4);
transition: transform 400ms ease;
}
.caption-image:hover + .caption-text,
.caption-text:hover {
transform: translateY(-100%);
}
<div class="caption">
<img class="caption-image" src="http://faron.eu/wp-content/uploads/2013/05/Cheese.jpg" />
<div class="caption-text">Some words about how cheesy it is to use a picture of cheese for this example!</div>
</div>
<div class="caption">
<img class="caption-image" src="https://top5ofanything.com/uploads/2015/05/Tomatoes.jpg" />
<div class="caption-text">There's nothing witty to say about a tomato, maybe some you say I say stuff. But honstly I can't think of anything...</div>
</div>
I'll give it to you even better: No javascript at all!
This is possible with pure CSS:
.tumb-wrapper {
position: relative;
overflow: hidden;
}
.text {
text-align: center;
background-color: grey;
width: 100%;
height: 10%;
font-size: 20px;
color: white;
opacity: 0.7;
display: block;
position: absolute;
bottom: -30px;
transition: 300ms;
left: 0;
}
.tumb-wrapper:hover .text {
bottom: 28px;
}
<div class="row">
<div class="col-md-6 col-sm-12">
<div class="tumb-wrapper">
<a href="http://www.bbc.com" target="_blank" class="image">
<img src="https://i.vimeocdn.com/portrait/8070603_300x300" class="project" alt="print-screen"/>
<div class="text">AAA</div>
</a>
</div>
</div>
<div class="col-md-6 col-sm-12">
<div class="tumb-wrapper">
<a href="http://www.cnn.com" target="_blank" class="image">
<img src="https://lh6.ggpht.com/mSKQgjFfPzrjqrG_d33TQZsDecOoVRF-jPKaMDoGIpMLLT1Q09ABicrXdQH6AZpLERY=w300" class="project" alt="print-screen"/>
<div class="text">BBB</div>
</a>
</div>
</div>
</div>
The transition css property animates whatever change you make. This way, when you hover over the .tumb-wrapper div, the .text div will slide up.
You should note however, that ancient IE versions won't be able to use this
I usually do this with only CSS.
Just save the first and second image right next to each other on one file... then you use css to change the position of the background image. To make things nicer i add a css-animation to the movement of the background image.
Example of my code:
<div id="thumb_Wrapper">
<div class="_Thumb">
<img src="images/Thumb.jpg" class="Animate_left">
</div>
</div>
The CSS
#_Container{position:absolute; bottom -60px; right:2px; width:626px; height:100px;}
._Thumb{position:relative; margin-right:4px; width:100px; height:80px; display:block; float:left; background:#EFEFEF; overflow:hidden;}
._Thumb > img{position:absolute; left:0; height:100%; background-size:cover; background-position:center;}
._Thumb > img:hover{left:-18px; cursor:pointer;}
CSS Animation
.Animate_left{transition:left .3s;}
Now all you have to do is swap out the image.
onHover - the image in the thumbnail will smoothly slide to the left; revealing the rest of the image/ showing the other image.
You can set how far to the left(or right) you want the thumb-image to first appear by adjusting the value of 'left' in the ._Thumb class.
You can set how far the image slides on hover by adjusting the img:hover{left:-18px} to what ever you like; instead of 18px.

Fix list absolute positioning (li's are hidden behind first two)

Problem is that when user hovers one li it makes width of li 100 percent of screen, so li needs absolute positioning to get over another li which is on the same line, but in this list I want 6 or more child, when I add other li's, it crashes. Help.
It must look like this (Full screen 50% width li's) http://i.imgur.com/dRb92rK.gif
JSFIDDLE:
https://jsfiddle.net/shotamickaia/pp658v6j/
$(function(){
$('.leftchild').hover(function(){
$('.left').css("z-index", "2");
$('.left').css("width", "100%");
},function(){
$('.left').css("z-index", "0");
$('.left').css("width", "50%");
});
$('.rightchild').hover(function(){
$('.right').css("z-index", "2");
$('.right').css("width", "100%");
},function(){
$('.right').css("z-index", "0");
$('.right').css("width", "50%");
});
function getCurrentScroll() {
return window.pageYOffset;
}
});
$(document).ready(function() {
function setSettings() {
windowWidth = $(window).width();
windowHeight = $(window).height();
width = (((50 * windowWidth) / 100)*50) / 100;
marginleft = ((((50 * windowWidth) / 100)*50) / 100) / 2;
margintop = (((50 * windowHeight) / 100)*50) / 100;
numitems = $(".slides li").length;
var myheight = (numitems * 75);
$('.leftchild').css('width', width);
$('.leftchild').css('marginLeft',marginleft);
$('.leftchild').css('marginTop',margintop);
$('.rightchild').css('width', width);
$('.rightchild').css('marginRight',marginleft);
$('.rightchild').css('marginTop',margintop);
};
setSettings();
$(window).resize(function() {
setSettings();
});
});
body,html {
margin:0;
padding:0;
height:100%;
background: white;
}
#reasons {
width: 100%;
float: left;
margin: 0;
height: auto;
padding: 0;
background: #f7f2ee;
}
.slides {
list-style-type: none;
padding: 0;
width: 100%;
height: 100%;
position: relative;
margin: 0;
}
.slides li {
height: 100vh;
width: 50%;
background-repeat: no-repeat;
background-position: center center;
background-attachment: fixed;
-webkit-background-size: cover;
-moz-background-size: cover;
-o-background-size: cover;
background-size: cover;
position: relative;
float: left;
transition: all .4s linear;
position: absolute;
width: 100%;
z-index: 0;
}
.slides li:nth-child(even) {
z-index: 1;
background-attachment: cover;
width: 50%;
right: 0;
}
.slides li:nth-child(even) summary {
width: 300px;
margin-right: 200px;
color: white;
text-align: center;
float: right;
}
.slides li:nth-child(3) {
margin-top: 50%;
}
.slides li summary {
color: white;
float: left;
text-align: center;
cursor: default;
}
.slides li summary h2 {
font-family: 'Proxima Nova Bold';
font-size: 48px;
text-transform: uppercase;
letter-spacing: 20px;
margin: 10% 0;
}
.slides li summary p {
width: 100%;
font-size: 16px;
text-align: center;
font-family: 'Andada';
font-weight: normal;
font-style: italic;
opacity: 0.95;
padding: 0;
margin: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section id="reasons">
<div class="slider">
<ul class="slides">
<li class="left" style="background-image: url(content/test1.jpg); background-color:black;">
<summary class="leftchild">
<h2>Test 1</h2>
<p>Test description</p>
</summary>
</li>
<li class="right" style="background-image: url(content/test2.jpg); background-color:red;">
<summary class="rightchild">
<h2>TEST 2</h2>
<p>Test description</p>
</summary>
</li>
<li class="left" style="background-image: url(content/test3.jpg); background-color:black;">
<summary class="leftchild">
<h2>Test 3</h2>
<p>Test description</p>
</summary>
</li>
<li class="right" style="background-image: url(content/test4.jpg); background-color:red;">
<summary class="rightchild">
<h2>TEST 4</h2>
<p>Test description</p>
</summary>
</li>
<li class="left" style="background-image: url(content/test5.jpg); background-color:black;">
<summary class="leftchild">
<h2>Test 5</h2>
<p>Test description</p>
</summary>
</li>
<li class="right" style="background-image: url(content/test6.jpg); background-color:red;">
<summary class="rightchild">
<h2>TEST 6</h2>
<p>Test description</p>
</summary>
</li>
<li class="left" style="background-image: url(content/test7.jpg); background-color:black;">
<summary class="leftchild">
<h2>Test 7</h2>
<p>Test description</p>
</summary>
</li>
<li class="right" style="background-image: url(content/test8.jpg); background-color:red;">
<summary class="rightchild">
<h2>TEST 8</h2>
<p>Test description</p>
</summary>
</li>
<li class="left" style="background-image: url(content/test9.jpg); background-color:black;">
<summary class="leftchild">
<h2>Test 9</h2>
<p>Test description</p>
</summary>
</li>
<li class="right" style="background-image: url(content/test10.jpg); background-color:red;">
<summary class="rightchild">
<h2>TEST 10</h2>
<p>Test description</p>
</summary>
</li>
</ul>
</div>
</section>
I solved this in pure css/html!! The only annoying bit is that you need a css declaration for every list item in order to set its initial width.
I used css left and right attributes instead of width, because I found that made things substantially easier.
Check it out: https://jsfiddle.net/gershy/k16mcgkb/2/
The idea is that all the li elements are absolutely positioned taking up all vertical space, and a portion of horizontal space. When an li is hovered its left and right are then both set to 0 (stretching all the way across its parent).
There's a neat effect as well that you will notice, that the li elements on either side of the hovered one become compressed. This is important because it helps avoid any z-index difficulties.
Here's the css that takes care of this (it's the most complicated part):
ul:hover > li {
left: 0; right: 100%;
}
ul > li:hover {
left: 0; right: 0;
z-index: 2;
}
ul > li:hover ~ li {
left: 100%; right: 0;
}
The 1st rule says that when the ul is hovered, ALL li elements need to squish over to the left side (left: 0; and right: 100%; tell an element to have 0 width at the left side of its parent).
The 2nd rule says that the specific li being hovered should stretch the entire way across its parent (and gain a higher z-index than its siblings, just in case)
The 3rd rule is the cool part and uses a css feature I've barely ever had to use; the ~ is the "general sibling selector" and selects all elements following a certain element. This rule tells only all li elements that are to the right of the hovered element to squish to the right side instead of the left, overwriting the effects of the 1st rule.
I hope you don't mind the "compression" effect, I understand that you didn't ask for it.
EDIT:
It's always been stackable, here it is with several items on top of each other.
The only thing that's really been added are !important modifiers on the hover-resizing rules, to ensure that no matter how specific the previous style rules are, the size is modified on hover.
https://jsfiddle.net/gershy/s3668f8h/

Add hover and thumbnail support with jQuery

Here is my code I'm using: http://plnkr.co/edit/qfL6mg3bUGYxX70dx1WV?p=preview
I'm trying to figure out how I can pause the slideshow when a user hovers over the large slider image and also, if the user clicks on a thumbnail how can I add the "selected" class like the first image with the blue border has?
Here is the html:
<div id="slider-container">
<ul class="slider">
<li>
<img src="http://placehold.it/350x150&text=1">
<div class="img-caption">
<h2>Test1</h2>
<p>Test 1 text</p>
</div>
</li>
<li>
<img src="http://placehold.it/350x150&text=2">
<div class="img-caption">
<h2>Test2</h2>
<p>Test 2 text</p>
</div>
</li>
<li>
<img src="http://placehold.it/350x150&text=3">
<div class="img-caption">
<h2>Test3</h2>
<p>Test 3 text</p>
</div>
</li>
<li>
<img src="http://placehold.it/350x150&text=4">
<div class="img-caption">
<h2>Test4</h2>
<p>Test 4 text</p>
</div>
</li>
</ul>
<!--/main slider slider-->
<!-- thumb navigation slider -->
<div id="slider-thumbs">
<!-- thumb navigation slider items -->
<ul class="list-inline">
<li> <a class="selected">
<img src="http://placehold.it/50x50&text=1">
</a></li>
<li> <a>
<img src="http://placehold.it/50x50&text=2">
</a></li>
<li> <a>
<img src="http://placehold.it/50x50&text=3">
</a></li>
<li> <a>
<img src="http://placehold.it/50x50&text=4">
</a></li>
</ul>
</div>
</div>
CSS:
#slider-container {
float: left;
}
.slider {
position: relative;
overflow: hidden;
margin: 0px;
padding: 0;
}
.slider li {
display: none;
top: 0;
left: 0;
list-style: none;
}
.img-caption {
background-color: #e3e4e4;
opacity: 0.8;
margin-top: -100px;
padding: 0px 0 0px 15px;
}
.img-caption h2 {
font-size: 28px;
text-transform: uppercase;
padding-top: 10px;
}
.img-caption p {
font-size: 14px;
margin-top: -20px;
padding-bottom: 10px;
}
.list-inline {
padding-left: 0;
list-style: none;
}
.list-inline>li {
display: inline-block;
padding-left: 1px;
padding-right: 1px;
}
.selected img {
border: 3px #0084d9 solid;
}
#slider-thumbs {
margin-top: -20px;
}
And JS:
jQuery(function($) {
var $slider = $('.slider');
var $slide = 'li';
var $transition_time = 0;
var $time_between_slides = 4000;
function slides(){
return $slider.find($slide);
}
slides().fadeOut();
slides().first().addClass('active');
slides().first().fadeIn($transition_time);
$interval = setInterval(
function(){
var $i = $slider.find($slide + '.active').index();
slides().eq($i).removeClass('active');
slides().eq($i).fadeOut($transition_time);
if (slides().length == $i + 1) $i = -1;
slides().eq($i + 1).fadeIn($transition_time);
slides().eq($i + 1).addClass('active');
}
, $transition_time + $time_between_slides
);
});
If you have any question let me know before down voting. I'll do my best for clarification. Thx
This should do : http://plnkr.co/edit/X2I1AFo2O1KOnnnBMiUg?p=preview
Thumbs are selected as slides are activated.
On user click thumbs are selected and same slide is activated.
On hover no action. (Thom-x's answer)
$("#slider-thumbs li a").click(function() {
var $i = $slider.find($slide + '.active').index();
slides().eq($i).removeClass('active');
slides().eq($i).fadeOut($transition_time);
var $j = $thumbs.find('li a.selected').parent().index();
thumbslist().eq($j).removeClass('selected');
$j = $(this).parent().index();
slides().eq($j).fadeIn($transition_time);
slides().eq($j).addClass('active');
$(this).addClass("selected");
});
I used :
$(".slider").hover(callback,callback)
Now you can pause the slider.
http://plnkr.co/edit/Qe3qq6v5g2FU3dVerUMc?p=preview
Edit :
Everything is working now (with some basic Jquery functions).

Categories

Resources