Infinity Loop Slider Concepts - javascript

I wonder what are the best(good readable code, pest practice code,reusability) concepts to build a Infinity-Image-Loop-Slider for a Website using JavaScript/jQuery? I dont what to know how to code the Slide show but what blueprint matches the requirements mention above.
The main focus of my question is how to arrange the pictures to get the impression of a infinity loop Slider.
By look at Code from different Sliders I came across two solutions:
-change the z-Index of all Images each time the next/previous image is displayed.
-change the Position of the Image in the DOM.
But examine and understanding the code of others is very time-consuming - that's why I ask this question :-)

tl;dr - JSBin Example: http://jsbin.com/ufoceq/8/
A simple approach to create an infinite image slider without too much effort is as follows: let say for the sake of simplicity that you have <n> images to slide in a loop, so that after the nth image the next one to visualize is the 1st (and vice-versa).
The idea is to create a clone of first and last image so that
the clone of the last image is prepended before the first one;
the clone of the first image is appended after the last one.
Whatever is the amount of your images, you will need to append at most only 2 cloned elements.
Again for the simplicity, let say that all images are 100px wide and they're wrapped in a container that you move left/right into a clipped mask with overflow: hidden. Then, all images can be easily aligned in a row with display: inline-block and white-space: nowrap set on the container (with flexbox now it is even easier).
For n = 4 The DOM structure would be something like this:
offset(px) 0 100 200 300 400 500
images | 4c | 1 | 2 | 3 | 4 | 1c
/* ^^ ^^
[ Clone of the last image ] [ Clone of the 1st image ]
*/
At the beginning, your container will be positioned with left: -100px (or also margin-left: -100px or even better (for a matter of performance) transform: translateX(-100px) ), so the slider can show the first image. To switch from an image to another you will need to apply a javascript animation over the same property you've previously chosen.
When your slider is currently at the 4th image, you have to switch from image 4 to 1c, so the idea is to execute a callback at the end of the animation that soon reposition your slider wrapper at the real 1st image offset (e.g. you set left: -100px to the container)
This is analogous when your slider is currently positioned on the 1st element: to show the previous image you just need to perform an animation from image 1 to 4c and when animation has been completed you just move the container so the slider is istantly positioned at the 4th image offset (e.g. you set left: -400px to the container).
You can see the effect on the above fiddle: this is the minimal js/jquery code I used (of course the code can be even optimized so the width of the items is not hardcoded into the script)
$(function() {
var gallery = $('#gallery ul'),
items = gallery.find('li'),
len = items.length,
current = 1, /* the item we're currently looking */
first = items.filter(':first'),
last = items.filter(':last'),
triggers = $('button');
/* 1. Cloning first and last item */
first.before(last.clone(true));
last.after(first.clone(true));
/* 2. Set button handlers */
triggers.on('click', function() {
var cycle, delta;
if (gallery.is(':not(:animated)')) {
cycle = false;
delta = (this.id === "prev")? -1 : 1;
/* in the example buttons have id "prev" or "next" */
gallery.animate({ left: "+=" + (-100 * delta) }, function() {
current += delta;
/**
* we're cycling the slider when the the value of "current"
* variable (after increment/decrement) is 0 or when it exceeds
* the initial gallery length
*/
cycle = (current === 0 || current > len);
if (cycle) {
/* we switched from image 1 to 4-cloned or
from image 4 to 1-cloned */
current = (current === 0)? len : 1;
gallery.css({left: -100 * current });
}
});
}
});
});
As mentioned before, this solution doesn't require really much effort and talking about performance, comparing this approach to a normal slider without looping, it only requires to make two additional DOM insertion when the slider is initialized and some (quite trivial) extra logic to manage a backward/forward loop.
Here is another example when you see two elements at once: in that case you need to clone more elements and make some simple changes to the logic
https://codepen.io/fcalderan/pen/bGbjZdz
I don't know if a simpler or better approach exists, but hope this helps anyway.
Note: if you need to also have a responsive gallery, maybe this answer may help too

I've just created the item slider: check it out:
https://github.com/lingtalfi/jItemSlider/blob/master/README.md
It's 600 lines of code, maybe you can simply browse it.
The idea behind it is inspired by the netflix slider (as of 2016-02-24).
Basically, it uses css transform translations, because those are the fastest/slickest in a browser.
http://eng.wealthfront.com/2015/05/19/performant-css-animations/
Now the basic concept behind the slide movement, is that you only display the current visible slice,
but you also have one invisible slice on the left, and another invisible slice on the right.
And, you also have two extra items, one on each side, so that your items look like this:
previous items - prev extra item - main items - next extra item - next items
Only the main items are visible.
The extra items are partially visible.
The previous and next items are invisible.
More details here:
https://github.com/lingtalfi/jItemSlider/blob/master/doc/conception.md
Now when you slide to the right (for instance), you basically append more items to the right side,
and then remove those from the left side.
This technique is the greatest I've encountered so far, because you don't deal with a long list of items (using
cloning without removing the invisible items), which can make your animation slower.
Note: my first try of this slider was actually cloning without removing, it works, but I don't like it:
https://github.com/lingtalfi/jInfiniteSlider
Also, it's item based (rather than pixels based), and in the end, that's what the user expects because
everything is always aligned, as it should be.

Vanila Javascript!! No-clone technique, getElementsByClassName to the rescue
document.getElementsByClassName selection is a live collection; any changes in DOM is updated in the stored variable unlike querySelector method.
In this technique, we just shift the first slide to the end if we reach the last slide while clicking right or we shift the last slide at the beginning when we reach the first slide while clicking left. Clone creation is not required here. The getElementsByClassName method gives us a live HTML collection to work with which updates as we make changes in the DOM. (In this case, changes in the order of divs)
Here is my GitHub Repository
// slider
const slides = document.getElementsByClassName("slide"); // this selection is a live collection; any changes in DOM is updated in the variable unlike querySelectors
const btnLeft = document.querySelector(`.btn-left`);
const btnRight = document.querySelector(`.btn-right`);
let currentSlideIndex = 0;
let lastSlideIndex = slides.length - 1;
// go to a slide;
function goToSlide(slideIndex) {
[...slides].forEach((s, i) => {
s.style.transform = `translateX(${100 * (i - slideIndex)}%)`
})
currentSlideIndex = slideIndex;
}
goToSlide(currentSlideIndex);
// make ready the next slide if current slide is the first or the last slide
function readyNextSlide() {
// if currentSlide is the last slide, shift the first slide to the end
if (currentSlideIndex === lastSlideIndex) {
slides[lastSlideIndex].insertAdjacentElement("afterend", slides[0]);
slides[lastSlideIndex].style.transform = `translateX(${100}%)`;
currentSlideIndex--; //this is because current slide is now the second last slide
}
// if currentSlide is the first slide, shift the last slide to the beginning
if (currentSlideIndex === 0) {
slides[0].insertAdjacentElement("beforebegin", slides[lastSlideIndex]);
slides[0].style.transform = `translateX(-${100}%)`;
currentSlideIndex++; //this is because current slide is now the second slide
}
}
// put the last slide in the beginning; ('if' condition is not necessary but providing if condition is future proof if user sets the initial slide to be shown as the last slide )
if (currentSlideIndex === lastSlideIndex || currentSlideIndex === 0) readyNextSlide();
// shift all slides left or right based on direction provided
function shiftSlides(direction) {
direction ? currentSlideIndex++ : currentSlideIndex--
if (currentSlideIndex === lastSlideIndex || currentSlideIndex === 0) readyNextSlide();
goToSlide(currentSlideIndex);
}
//button click events
btnRight.addEventListener("click", shiftSlides.bind(null, 1));
btnLeft.addEventListener("click", shiftSlides.bind(null, 0));
body {
display: grid;
height: 100vh;
width: 100vw;
align-items: center;
align-content: center;
justify-content: center;
}
.slider {
position: relative;
width: 600px;
height: 300px;
transform: scale(0.8);
overflow: hidden; /* remove overflow to see what's going on*/
}
.slide {
position: absolute;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
transition: transform 1s;
}
.slide b {
position: absolute;
font-size: 10em;
color: black;
opacity: 0.6;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.s1 {
background-color: cornflowerblue;
}
.s2 {
background-color: bisque;
}
.s3 {
background-color: coral;
}
.s4 {
background-color: thistle;
}
.btn {
position: absolute;
top: 50%;
z-index: 10;
border: none;
background: crimson;
font-family: inherit;
color: white;
height: 5.5rem;
width: 5.5rem;
font-size: 3.25rem;
cursor: pointer;
}
.btn-left {
left: 6%;
transform: translate(-50%, -50%);
}
.btn-right {
right: 6%;
transform: translate(50%, -50%);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Infinity Looping Rotating slider</title>
<link rel="stylesheet" href="slider.css">
<script src="slider.js" defer></script>
</head>
<body>
<div class="slider">
<div class="slide s1"><b>1</b></div>
<div class="slide s2"><b>2</b></div>
<div class="slide s3"><b>3</b></div>
<div class="slide s4"><b>4</b></div>
<button class="btn btn-left">←</button>
<button class="btn btn-right">→</button>
</div>
<p>
<b>
This is my response to a questing in StackOverflow about infinity loop slider.<br>
My github repo is Infinity loop Slider by Dibakash
</b>
</p>
</body>
</html>

Thanks a lot of this article!
I had update and used above code.
I hope this will help everyone.
Poor developer.
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Directive slider</title>
<style>
/* 四联切换焦点图 */
.slides-wrapper{ position: relative; width: 100%; margin: 10px 0; }
.gallery { position: relative; width: 1200px; height: 180px; overflow:hidden; }
.gallery ul { font-size: 0; white-space: nowrap; position: absolute; top: 0; left: -1200px; margin: 0; padding: 0; }
.gallery li { display: inline-block; vertical-align: top; width: 1200px; height: 180px; white-space: normal; }
.gallery li img{ width: 298px; height:180px; padding: 1px; }
.gallery .arrow { background: url(/shop/templates/default/images/home_bg.png) no-repeat; background-size: 150px 223px; width: 35px; height: 70px; position: absolute; z-index: 2; top: 50px; cursor: pointer; opacity: 0;}
.gallery .prev { background-position: 1px -92px; left: 0;}
.gallery .next { background-position: -30px -92px; right: 0px;}
</style>
<style type="text/css">
.demo_wrapper{
margin: 0 auto;
width: 1200px;
}
.demo_wrapper .title{
text-align: center;
}
</style>
</head>
<body>
<div class="demo_wrapper">
<div class="title">
<h1>Directive slider (Published by fenmingyu)</h1>
</div>
<!-- demo content -->
<div class="slides-wrapper">
<div class="gallery" id="top_sale_gallery">
<ul>
<li>
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-1.jpg?234" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-2.jpg?752" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-3.jpg?320" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-4.jpg?365" alt="">
</li>
<li>
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-1.jpg?852" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-2.jpg?746" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-3.jpg?525" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-4.jpg?550" alt="">
</li>
</ul>
<div class='arrow prev'></div>
<div class='arrow next'></div>
</div>
<div class="gallery" id="top_goods_gallery">
<ul>
<li>
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-3-1.jpg?793" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-3-2.jpg?180" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-3-3.jpg?550" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-3-4.jpg?851" alt="">
</li>
<li>
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-1.jpg?234" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-2.jpg?752" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-3.jpg?320" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-4.jpg?365" alt="">
</li>
<li>
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-1.jpg?852" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-2.jpg?746" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-3.jpg?525" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-4.jpg?550" alt="">
</li>
</ul>
<div class='arrow prev'></div>
<div class='arrow next'></div>
</div>
<div style="clear: both;"></div>
</div>
</div>
</body>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$(function() {
$.fn.gallery = function(settings) {
var defaults = {
time: 3000,
direction:1
};
var settings = $.extend(defaults, settings);
var gallery_wrapper = $(this),
gallery = gallery_wrapper.find('ul'),
items = gallery.find('li'),
len = items.length,
current = 1, /* the current item we're looking */
first = items.filter(':first'),
last = items.filter(':last'),
w = gallery.find('li').width(),
triggers = gallery_wrapper.find('.arrow');
var show_slide = function(direction,w){
gallery.animate({ left: "+=" + (-w * direction) }, function() {
current += direction;
/**
* we're cycling the slider when the the value of "current"
* variable (after increment/decrement) is 0 or when it exceeds
* the initial gallery length
*/
cycle = !!(current === 0 || current > len);
if (cycle) {
/* we switched from image 1 to 4-cloned or
from image 4 to 1-cloned */
current = (current === 0)? len : 1;
gallery.css({left: -w * current });
}
});
};
var picTimer = setInterval(function() {
show_slide(settings.direction,w);
},
settings.time);
return this.each(function(){
/* 1. Cloning first and last item */
first.before(last.clone(true));
last.after(first.clone(true));
/* 2. Set button handlers */
triggers.on('click', function() {
if (gallery.is(':not(:animated)')) {
var cycle = false;
settings.direction = ($(this).hasClass('prev'))? -1 : 1;
/* in the example buttons have id "prev" or "next" */
show_slide(settings.direction,w);
}
clearInterval(picTimer);
picTimer = setInterval(function() {
show_slide(settings.direction,w);
},
settings.time);
});
/* hover show arrows*/
show_slide(settings.direction,w);
gallery_wrapper.hover(function() {
$(this).find(".arrow").css("opacity", 0.0).stop(true, false).animate({
"opacity": "0.3"
},
300);
},function(){
$(this).find(".arrow").css("opacity", 0.3).stop(true, false).animate({
"opacity": "0"
},
300);
});
});
};
$('#top_goods_gallery.gallery').gallery();
$('#top_sale_gallery.gallery').gallery({
time: 5000,
direction:-1
});
});
</script>
</html>
te and use this in my project.

Related

CSS position elements along ring of a circle [duplicate]

How can I position several <img> elements into a circle around another and have those elements all be clickable links as well? I want it to look like the picture below, but I have no idea how to achieve that effect.
Is this even possible?
2020 solution
Here's a more modern solution I use these days.
I start off by generating the HTML starting from an array of images. Whether the HTML is generated using PHP, JS, some HTML preprocessor, whatever... this matters less as the basic idea behind is the same.
Here's the Pug code that would do this:
//- start with an array of images, described by url and alt text
- let imgs = [
- {
- src: 'image_url.jpg',
- alt: 'image alt text'
- } /* and so on, add more images here */
- ];
- let n_imgs = imgs.length;
- let has_mid = 1; /* 0 if there's no item in the middle, 1 otherwise */
- let m = n_imgs - has_mid; /* how many are ON the circle */
- let tan = Math.tan(Math.PI/m); /* tangent of half the base angle */
.container(style=`--m: ${m}; --tan: ${+tan.toFixed(2)}`)
- for(let i = 0; i < n_imgs; i++)
a(href='#' style=i - has_mid >= 0 ? `--i: ${i}` : null)
img(src=imgs[i].src alt=imgs[i].alt)
The generated HTML looks as follows (and yes, you can write the HTML manually too, but it's going to be a pain to make changes afterwards):
<div class="container" style="--m: 8; --tan: 0.41">
<a href='#'>
<img src="image_mid.jpg" alt="alt text"/>
</a>
<a style="--i: 1">
<img src="first_img_on_circle.jpg" alt="alt text"/>
</a>
<!-- the rest of those placed on the circle -->
</div>
In the CSS, we decide on a size for the images, let's say 8em. The --m items are positioned on a circle and it's if they're in the middle of the edges of a polygon of --m edges, all of which are tangent to the circle.
If you have a hard time picturing that, you can play with this interactive demo which constructs the incircle and circumcircle for various polygons whose number of edges you pick by dragging the slider.
This tells us that the size of the container must be twice the radius of the circle plus twice half the size of the images.
We don't yet know the radius, but we can compute it if we know the number of edges (and therefore the tangent of half the base angle, precomputed and set as a custom property --tan) and the polygon edge. We probably want the polygon edge to be a least the size of the images, but how much we leave on the sides is arbitrary. Let's say we have half the image size on each side, so the polygon edge is twice the image size. This gives us the following CSS:
.container {
--d: 6.5em; /* image size */
--rel: 1; /* how much extra space we want between images, 1 = one image size */
--r: calc(.5*(1 + var(--rel))*var(--d)/var(--tan)); /* circle radius */
--s: calc(2*var(--r) + var(--d)); /* container size */
position: relative;
width: var(--s); height: var(--s);
background: silver /* to show images perfectly fit in container */
}
.container a {
position: absolute;
top: 50%; left: 50%;
margin: calc(-.5*var(--d));
width: var(--d); height: var(--d);
--az: calc(var(--i)*1turn/var(--m));
transform:
rotate(var(--az))
translate(var(--r))
rotate(calc(-1*var(--az)))
}
img { max-width: 100% }
See the old solution for an explanation of how the transform chain works.
This way, adding or removing an image from the array of images automatically arranges the new number of images on a circle such that they're equally spaced out and also adjusts the size of the container. You can test this in this demo.
OLD solution (preserved for historical reasons)
Yes, it is very much possible and very simple using just CSS. You just need to have clear in mind the angles at which you want the links with the images (I've added a piece of code at the end just for showing the angles whenever you hover one of them).
You first need a wrapper. I set its diameter to be 24em (width: 24em; height: 24em; does that), you can set it to whatever you want. You give it position: relative;.
You then position your links with the images in the center of that wrapper, both horizontally and vertically. You do that by setting position: absolute; and then top: 50%; left: 50%; and margin: -2em; (where 2em is half the width of the link with the image, which I've set to be 4em - again, you can change it to whatever you wish, but don't forget to change the margin in that case).
You then decide on the angles at which you want to have your links with the images and you add a class deg{desired_angle} (for example deg0 or deg45 or whatever). Then for each such class you apply chained CSS transforms, like this:
.deg{desired_angle} {
transform: rotate({desired_angle}) translate(12em) rotate(-{desired_angle});
}
where you replace {desired_angle} with 0, 45, and so on...
The first rotate transform rotates the object and its axes, the translate transform translates the object along the rotated X axis and the second rotate transform brings back the object into position.
The advantage of this method is that it is flexible. You can add new images at different angles without altering the current structure.
CODE SNIPPET
.circle-container {
position: relative;
width: 24em;
height: 24em;
padding: 2.8em;
/*2.8em = 2em*1.4 (2em = half the width of a link with img, 1.4 = sqrt(2))*/
border: dashed 1px;
border-radius: 50%;
margin: 1.75em auto 0;
}
.circle-container a {
display: block;
position: absolute;
top: 50%; left: 50%;
width: 4em; height: 4em;
margin: -2em;
}
.circle-container img { display: block; width: 100%; }
.deg0 { transform: translate(12em); } /* 12em = half the width of the wrapper */
.deg45 { transform: rotate(45deg) translate(12em) rotate(-45deg); }
.deg135 { transform: rotate(135deg) translate(12em) rotate(-135deg); }
.deg180 { transform: translate(-12em); }
.deg225 { transform: rotate(225deg) translate(12em) rotate(-225deg); }
.deg315 { transform: rotate(315deg) translate(12em) rotate(-315deg); }
<div class='circle-container'>
<a href='#' class='center'><img src='image.jpg'></a>
<a href='#' class='deg0'><img src='image.jpg'></a>
<a href='#' class='deg45'><img src='image.jpg'></a>
<a href='#' class='deg135'><img src='image.jpg'></a>
<a href='#' class='deg180'><img src='image.jpg'></a>
<a href='#' class='deg225'><img src='image.jpg'></a>
<a href='#' class='deg315'><img src='image.jpg'></a>
</div>
Also, you could further simplify the HTML by using background images for the links instead of using img tags.
EDIT: example with fallback for IE8 and older (tested in IE8 and IE7)
Here is the easy solution without absolute positioning:
.container .row {
margin: 20px;
text-align: center;
}
.container .row img {
margin: 0 20px;
}
<div class="container">
<div class="row">
<img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
<img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
</div>
<div class="row">
<img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
<img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
<img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
</div>
<div class="row">
<img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
<img src="https://ssl.gstatic.com/s2/oz/images/faviconr2.ico" alt="" width="64" height="64">
</div>
</div>
http://jsfiddle.net/mD6H6/
Using the solution proposed by #Ana:
transform: rotate(${angle}deg) translate(${radius}px) rotate(-${angle}deg)
I created the following jsFiddle that places circles dynamically using plain JavaScript (jQuery version also available).
The way it works is rather simple:
document.querySelectorAll( '.ciclegraph' ).forEach( ( ciclegraph )=>{
let circles = ciclegraph.querySelectorAll( '.circle' )
let angle = 360-90, dangle = 360 / circles.length
for( let i = 0; i < circles.length; ++i ){
let circle = circles[i]
angle += dangle
circle.style.transform = `rotate(${angle}deg) translate(${ciclegraph.clientWidth / 2}px) rotate(-${angle}deg)`
}
})
.ciclegraph {
position: relative;
width: 500px;
height: 500px;
margin: calc(100px / 2 + 0px);
}
.ciclegraph:before {
content: "";
position: absolute;
top: 0; left: 0;
border: 2px solid teal;
width: calc( 100% - 2px * 2);
height: calc( 100% - 2px * 2 );
border-radius: 50%;
}
.ciclegraph .circle {
position: absolute;
top: 50%; left: 50%;
width: 100px;
height: 100px;
margin: calc( -100px / 2 );
background: teal;
border-radius: 50%;
}
<div class="ciclegraph">
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
</div>
Building off #Ana's excellent answer, I created this dynamic version that allows you to add and remove elements from the DOM and maintain proportionate spacing between the elements - check out my fiddle: https://jsfiddle.net/skwidbreth/q59s90oy/
var list = $("#list");
var updateLayout = function(listItems) {
for (var i = 0; i < listItems.length; i++) {
var offsetAngle = 360 / listItems.length;
var rotateAngle = offsetAngle * i;
$(listItems[i]).css("transform", "rotate(" + rotateAngle + "deg) translate(0, -200px) rotate(-" + rotateAngle + "deg)")
};
};
$(document).on("click", "#add-item", function() {
var listItem = $("<li class='list-item'>Things go here<button class='remove-item'>Remove</button></li>");
list.append(listItem);
var listItems = $(".list-item");
updateLayout(listItems);
});
$(document).on("click", ".remove-item", function() {
$(this).parent().remove();
var listItems = $(".list-item");
updateLayout(listItems);
});
#list {
background-color: blue;
height: 400px;
width: 400px;
border-radius: 50%;
position: relative;
}
.list-item {
list-style: none;
background-color: red;
height: 50px;
width: 50px;
position: absolute;
top: 50%;
left: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<ul id="list"></ul>
<button id="add-item">Add item</button>
Here is a version I made in React from the examples here.
CodeSandbox Example
import React, { useRef, useEffect } from "react";
import "./styles.css";
export default function App() {
const graph = useRef(null);
useEffect(() => {
const ciclegraph = graph.current;
const circleElements = ciclegraph.childNodes;
let angle = 360 - 90;
let dangle = 360 / circleElements.length;
for (let i = 0; i < circleElements.length; i++) {
let circle = circleElements[i];
angle += dangle;
circle.style.transform = `rotate(${angle}deg) translate(${ciclegraph.clientWidth /
2}px) rotate(-${angle}deg)`;
}
}, []);
return (
<div className="App">
<div className="ciclegraph" ref={graph}>
<div className="circle" />
<div className="circle" />
<div className="circle" />
<div className="circle" />
<div className="circle" />
<div className="circle" />
</div>
</div>
);
}
You can certainly do it with pure css or use JavaScript. My suggestion:
If you already know that the images number will never change just calculate your styles and go with plain css (pros: better performances, very reliable)
If the number can vary either dynamically in your app or just may vary in the future go with a Js solution (pros: more future-proof)
I had a similar job to do, so I created a script and open sourced it here on Github for anyone who might need it. It just accepts some configuration values and simply outputs the CSS code you need.
If you want to go for the Js solution here's a simple pointer that can be useful to you. Using this html as a starting point being #box the container and .dot the image/div in the middle you want all your other images around:
Starting html:
<div id="box">
<div class="dot"></div>
<img src="my-img.jpg">
<!-- all the other images you need-->
</div>
Starting Css:
#box{
width: 400px;
height: 400px;
position: relative;
border-radius: 100%;
border: 1px solid teal;
}
.dot{
position: absolute;
border-radius: 100%;
width: 40px;
height: 40px;
left: 50%;
top: 50%;
margin-left: -20px;
margin-top: -20px;
background: rebeccapurple;
}
img{
width: 40px;
height: 40px;
position: absolute;
}
You can create a quick function along these lines:
var circle = document.getElementById('box'),
imgs = document.getElementsByTagName('img'),
total = imgs.length,
coords = {},
diam, radius1, radius2, imgW;
// get circle diameter
// getBoundingClientRect outputs the actual px AFTER transform
// using getComputedStyle does the job as we want
diam = parseInt( window.getComputedStyle(circle).getPropertyValue('width') ),
radius = diam/2,
imgW = imgs[0].getBoundingClientRect().width,
// get the dimensions of the inner circle we want the images to align to
radius2 = radius - imgW
var i,
alpha = Math.PI / 2,
len = imgs.length,
corner = 2 * Math.PI / total;
// loop over the images and assign the correct css props
for ( i = 0 ; i < total; i++ ){
imgs[i].style.left = parseInt( ( radius - imgW / 2 ) + ( radius2 * Math.cos( alpha ) ) ) + 'px'
imgs[i].style.top = parseInt( ( radius - imgW / 2 ) - ( radius2 * Math.sin( alpha ) ) ) + 'px'
alpha = alpha - corner;
}
You can see a live example here
There is no way to magically place clickable items in a circle around another element with CSS.
The way how I would do this is by using a container with position:relative;. And then place all the elements with position:absolute; and using top and left to target it's place.
Even though you haven't placed jquery in your tags it might be best to use jQuery / javascript for this.
First step is placing your center image perfectly in the center of the container using position:relative;.
#centerImage {
position:absolute;
top:50%;
left:50%;
width:200px;
height:200px;
margin: -100px 0 0 -100px;
}
After that you can place the other elements around it by using an offset() of the centerImage minus the offset() of the container. Giving you the exact top and left of the image.
var left = $('#centerImage').offset().left - $('#centerImage').parent().offset().left;
var top = $('#centerImage').offset().top - $('#centerImage').parent().offset().top;
$('#surroundingElement1').css({
'left': left - 50,
'top': top - 50
});
$('#surroundingElement2').css({
'left': left - 50,
'top': top
});
$('#surroundingElement3').css({
'left': left - 50,
'top': top + 50
});
What I've done here is placing the elements relative to the centerImage. Hope this helps.
You could do it like this: fiddle
Don't mind the positioning, its a quick example
The first step is to have 6 long columnar boxes:
The second step is to use position: absolute and move them all into the middle of your container:
And now rotate them around the pivot point located at the bottom center. Use :nth-child to vary rotation angles:
div {
transform-origin: bottom center;
#for $n from 0 through 7 {
&:nth-child(#{$n}) {
rotate: (360deg / 6) * $n;
}
}
Now all you have to do is to locate your images at the far end of every column, and compensate the rotation with an anti-rotation :)
Full source:
<div class="flower">
<div class="petal">1</div>
<div class="petal">2</div>
<div class="petal">3</div>
<div class="petal">4</div>
<div class="petal">5</div>
<div class="petal">6</div>
</div>
.flower {
width: 300px;
height: 300px;
// We need a relative position
// so that children can have "position:abolute"
position: relative;
.petal {
// Make sure petals are visible
border: 1px solid #999;
// Position them all in one point
position: absolute; top: 0; left: 50%;
display: inline-block;
width: 30px; height: 150px;
// Rotation
transform-origin: bottom center;
#for $n from 0 through 7 {
&:nth-child(#{$n}) {
// Petal rotation
$angle: (360deg / 6) * $n;
rotate: $angle;
// Icon anti-rotation
.icon { rotate: -$angle; }
}
}
}
}
See CodePen

Jquery function isn't adding class to Dom elements when it should be. Trying to build a button function slideshow

I'm trying to create a slideshow for a project.
The code I've built is fairly simple but for some reason I can only make the next arrows work, not the previous.
When you click next it removes the class active from the current image, adds that class to the next image and changes the display to the new active image.
When you click previous it removes the active class but doesn't add any classes to any other elements. It then changes the display to the final image for some reason.
I've tried rearranging the order that the functions are called in. I've also tried to see what happens when the active class is added to the last image (it has the same problem but in reverse, so now next doesn't work but previous is fine).
var activeSlide = $('.active');
var nextSlide = activeSlide.next('.slide');
var prevSlide = activeSlide.prev('.slide');
var arrow = $('.arrow');
var firstSlide = $('.first');
var lastSlide = $('.last');
// slideshow functions
// next arrow
function nextArrow () {
if (!activeSlide.hasClass('last')) {
activeSlide.removeClass('active');
nextSlide.addClass('active');
activeSlide = nextSlide;
nextSlide = activeSlide.next('.slide');
// check if new slide is last slide and remove the click button
if (activeSlide.hasClass('last')) {
$('.next').fadeOut();
}
}
};
// previous arrow
function prevArrow () {
if(!activeSlide.hasClass('first')) {
activeSlide.removeClass('active');
prevSlide.addClass('active');
activeSlide = prevSlide;
prevSlide = activeSlide.prev('.slide');
// check if new slide is the first slide and remove the click button
if (activeSlide.hasClass('first')) {
$('.previous').fadeOut();
}
}
};
//click element and call functions
$('.arrow').click( function () {
if ($(this).hasClass('next')) {
nextArrow();
} else {
prevArrow();
}
});
#slideshow {
position: relative;
height: 400px;
width: 600px;
margin: 15% auto;
}
.slide {
position: absolute;
top: 0;
left: 0;
z-index: 8;
height: 100%;
width: 100%;
}
.active {
z-index: 10;
}
.arrow {
text-decoration: none;
display: inline-block;
padding: 8px 16px;
}
.arrow:hover {
background-color: #ddd;
color: black;
opacity: 0.9;
cursor: pointer;
}
.previous {
left: 0;
}
.next {
right: 0;
}
.arrow {
z-index: 11;
background-color: #ddd;
color: black;
position: absolute;
top: 50%;
opacity: 0.5;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="slideshow">
<div id="slides">
<img class="slide active first" src="Toscana 1.jpg" alt="image of toscana, slideshow image 1" />
<img class="slide" src="Toscana 2.jpg" alt="image of toscana, slideshow image 1" />
<img class="slide" src="Toscana 3.jpg" alt="image of toscana, slideshow image 2" />
<img class="slide last" src="Toscana 4.jpg" alt="image of toscana, slideshow image 3" />
</div>
<div class="previous arrow">‹</div>
<div class="next arrow">›</div>
</div>
<script src="javascript/practice.js"></script>
In theory you should be able to click next and see the next image in the sequence. Then when you want to see the previous image in the sequence you should be able to click previous whereby it will remove the active class from the current image and add it to the image before.
Really appreciate the help understanding what's going wrong if anyone is able to help at all.
You're depending on global variables to maintain your program state, but aren't always managing to keep the state of the variables matching up with the state of the DOM.
It's probably better to use the DOM as a single source of truth: the "active" slide is whichever node currently has the "active" class, and you can calculate the next and previous ones based on its position.
This also needed some work on the "next" / "previous" button visibility: you were hiding buttons at the end and beginning of the range, but never brought them back; you also need to load with the "previous" button disabled initially.
//No global variables. Use $('.active') to determine the currently active slide
// next arrow
function nextArrow() {
var activeSlide = $('.active');
if (activeSlide.hasClass('last')) return; // bail if the user managed to click the 'next' button while it was fading out
activeSlide.removeClass('active');
activeSlide.next().addClass('active');
// $('.active') is now the "next" slide
if ($('.active').hasClass('last')) {
$('.next').fadeOut();
}
// Always bring back the "previous" button when user hits next:
$('.previous').fadeIn();
};
// previous arrow
function prevArrow() {
var activeSlide = $('.active');
if (activeSlide.hasClass('first')) return;
activeSlide.removeClass('active');
activeSlide.prev().addClass('active');
if ($('.active').hasClass('first')) {
$('.previous').fadeOut();
}
$('.next').fadeIn();
};
//click element and call functions
// removing the unnecessary intermediate function here:
$('.next').click(nextArrow)
$('.previous').click(prevArrow)
#slideshow {
position: relative;
height: 200px;
width: 300px;
margin: 15% auto;
}
.slide {
position: absolute;
top: 0;
left: 0;
z-index: 8;
height: 100%;
width: 100%;
}
.active {
z-index: 10;
}
.arrow {
text-decoration: none;
display: inline-block;
padding: 8px 16px;
}
.arrow:hover {
background-color: #ddd;
color: black;
opacity: 0.9;
cursor: pointer;
}
.previous {
left: 0;
display:none;
}
.next {
right: 0;
}
.arrow {
z-index: 11;
background-color: #ddd;
color: black;
position: absolute;
top: 50%;
opacity: 0.5;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="slideshow">
<div id="slides">
<img class="slide active first" src="https://placehold.it/600x400" alt="image of toscana, slideshow image 1" />
<img class="slide" src="https://placehold.it/601x401" alt="image of toscana, slideshow image 2" />
<img class="slide" src="https://placehold.it/602x402" alt="image of toscana, slideshow image 1" />
<img class="slide last" src="https://placehold.it/603x403" alt="image of toscana, slideshow image 1" />
</div>
<div class="previous arrow">‹</div>
<div class="next arrow">›</div>
</div>
You're not setting a prevSlide in your next arrow function. so when you start, prevSlide is null. then you click the next arrow button and you set the active slide to the nextSlide, then set the nextSlide to one after the active, but you're not setting the previous slide so it stays null
eg slide 1 = current-slide, slide 2 = about-to-be-active, slide 3 = about-to-be-next
operation of clicking the next arrow should be:
set prevSlide to current-slide (this action doesn't happen)
set activeSlide to next-slide
set nextSlide to next-slide.next
similarly in your prevArrow, you need to set the nextSlide
you can try the class $ ('. active');
if(!activeSlide.hasClass('first')) {
var currentSlide = $('.active');
var prevSlide = currentSlide.prev();
currentSlide.removeClass('active');
prevSlide.addClass('active');

jquery increase/decrease image contrast on scroll

This site I am developing is using HTML5, CSS3, Bootstrap 4, and Jquery. I would like to have a scroll effect on a full-screen background-image that is at the very top of my page (100vh hero banner type thing). I am trying to gradually increase the contrast (css filter: contrast(some%)) of an image as the user scrolls down (its fine if the image is completely unrecognizable by the time it leaves viewport).
I have some Jquery that somewhat does the effect I am looking for, however I would like the effect to be more gradual.
The main issue I am having is that when the user scrolls back to the top of the page the contrast value gets set to 0% leaving a completely grayed out image. What I would like is for the contrast to gradually decrease back to normal (100%) as the user scrolls back up all the way to the top of the page.
I have set up a very simplified codepen. I couldn't get a css background-image url value to reference an external link from codepen, so I am targeting the effect on a full screen image ().
Thanks!
Link to the Pen: [codepen-link][1]
[1]: http://codepen.io/wdzajicek/pen/MVovZE
See code below in snippet
$(document).ready(function (){
$(window).scroll(function(){
var pixelstop = $(window).scrollTop();
$(".myimage ").css("filter", "contrast(" + pixelstop + "%)");
});
});
.header {
height: 100vh;
}
.myimage {
position:absolute;
top: 0;
left: 0;
min-width: 100%;
width; 100%;
z-index: -1;
}
.jumbotron {
position: relative;
background-color: unset;
margin-top: 150px;
z-index: 999;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<header class="header text-center">
<img src="https://raw.githubusercontent.com/wdzajicek/portfolio/master/assets/img/header-bg.jpg" class="myimage" alt="">
</header>
There is the main problem in $(window).scrollTop(); it will return 0 value
that's why contrast value gets set to 0% leaving a completely grayed out image
var pixelstop = $(window).scrollTop();
replace the code with
var pixelstop = 100+100*$(window).scrollTop()/$(window).height();
don't just copy this code please understand thanks.
$(document).ready(function (){
$(window).scroll(function(){
var pixelstop = 100+100*$(window).scrollTop()/$(window).height();
console.log(pixelstop);
$(".myimage ").css("filter", "contrast(" + pixelstop + "%)");
});
});
.header {
height: 100vh;
}
.myimage {
position:absolute;
top: 0;
left: 0;
min-width: 100%;
width; 100%;
z-index: -1;
}
.jumbotron {
position: relative;
background-color: unset;
margin-top: 150px;
z-index: 999;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<header class="header text-center">
<img src="https://raw.githubusercontent.com/wdzajicek/portfolio/master/assets/img/header-bg.jpg" class="myimage" alt="">
</header>
100 is default value of filter contrast not 0. that's why the background is grey out because it reaches zero.

Advanced Slider Customization

I am trying to achieve below image type of slider using Superslides and Bxslider.
Slider Explanation:
Black boxes are points/stops.
Blue box is car.
Whenever car crosses the half way stop,I need to change the red slider to next one.
User can use mouse scroll or arrow keys to move car forward or backward & on mobile using swipe forward or backward.
What I have done using Superslides and Bxslider
Using callback functions of bxslider to animate the car, but stuck.
Help: I need ideas how to achieve such result.What kind of slider I can use to acheieve something like this.
Reference link but with jQuery
(function($) {
var elem = $.jInvertScroll(['.scroll'], // an array containing the selector(s) for the elements you want to animate
{
height: 6000, // optional: define the height the user can scroll, otherwise the overall length will be taken as scrollable height
onScroll: function(percent) { //optional: callback function that will be called when the user scrolls down, useful for animating other things on the page
console.log(percent);
}
});
$(window).resize(function() {
if ($(window).width() <= 768) {
elem.destroy();
}
else {
elem.reinitialize();
}
});
}(jQuery));
html,
body
{
padding: 0;
margin: 0;
font-family: Arial, sans-serif;
}
/* hide horizontal scrollbars, since we use the vertical ones to scroll to the right */
body
{
overflow-x: hidden;
background: url('../images/bg.jpg') repeat top left;
}
h1
{
font-size: 20px;
font-weight: normal;
color: #2e6e80;
}
/**
* important: keep position fixed, you can however use top:0 instead of bottom:0
* if you want to make it stick to the top of the browser
*/
.scroll
{
position: fixed;
bottom: 0;
left: 0;
}
/**
* z-index ordering of the different layers, do this for your layers,
* also assign absolute width (to prevent issues if the script gets executed before the images get loaded)
*/
.horizon
{
z-index: 1;
width: 3000px;
}
.middle
{
z-index: 500;
width: 4000px;
}
.front
{
z-index: 1000;
width: 6000px;
}
<h1>jInvertScroll Example</h1>
<div class="horizon scroll">
<img src="https://raw.githubusercontent.com/pixxelfactory/jInvertScroll/master/examples/images/horizon.png" alt="" />
</div>
<div class="middle scroll">
<img src="https://raw.githubusercontent.com/pixxelfactory/jInvertScroll/master/examples/images/middle.png" alt="" />
</div>
<div class="front scroll">
<img src="https://raw.githubusercontent.com/pixxelfactory/jInvertScroll/master/examples/images/front.png" alt="" />
</div>
<script src="http://www.pixxelfactory.net/jInvertScroll/js/jquery.min.js"></script>
<script src="http://www.pixxelfactory.net/jInvertScroll/js/jquery.jInvertScroll.js"></script>

How do I achieve equal height divs (positioned side by side) with HTML / CSS ?

I have two divs inside of a container. One on the left, one on the right, side by side. How am I able to make each one be of equal height, even though they have different content.
For example, the right div has a lot of content, and is double the height of the left div, how do I make the left div stretch to the same height of the right div?
Is there some JavaScript (jQuery) code to accomplish this?
You could use jQuery, but there are better ways to do this.
This sort of question comes up a lot and there are generally 3 answers...
1. Use CSS
This is the 'best' way to do it, as it is the most semantically pure approach (without resorting to JS, which has its own problems). The best way is to use the display: table-cell and related values. You could also try using the faux background technique (which you can do with CSS3 gradients).
2. Use Tables
This seems to work great, but at the expense of having an unsemantic layout. You'll also cause a stir with purists. I have all but avoided using tables, and you should too.
3. Use jQuery / JavaScript
This benefits in having the most semantic markup, except with JS disabled, you will not get the effect you desire.
Here's a way to do it with pure CSS, however, as you'll notice in the example (which works in IE 7 and Firefox), borders can be difficult - but they aren't impossible, so it all depends what you want to do. This example assumes a rather common CSS structure of body > wrapper > content container > column 1 and column 2.
The key is the bottom margin and its canceling padding.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Equal Height Columns</title>
<style type="text/css">
<!--
* { padding: 0; margin: 0; }
#wrapper { margin: 10px auto; width: 600px; }
#wrapper #main_container { width: 590px; padding: 10px 0px 10px 10px; background: #CCC; overflow: hidden; border-bottom: 10px solid #CCC; }
#wrapper #main_container div { float: left; width: 263px; background: #999; padding: 10px; margin-right: 10px; border: 1px solid #000; margin-bottom: -1000px; padding-bottom: 1000px; }
#wrapper #main_container #right_column { background: #FFF; }
-->
</style>
</head>
<body>
<div id="wrapper">
<div id="main_container">
<div id="left_column">
<p>I have two divs inside of a container. One on the left, one on the right, side by side. How am I able to make each one be of equal height, even though they have different content.</p>
</div><!-- LEFT COLUMN -->
<div id="right_column">
<p>I have two divs inside of a container. One on the left, one on the right, side by side. How am I able to make each one be of equal height, even though they have different content.</p>
<p> </p>
<p>For example, the right div has a lot of content, and is double the height of the left div, how do I make the left div stretch to the same height of the right div?</p>
<p> </p>
<p>Is there some JavaScript (jQuery) code to accomplish this?</p>
</div><!-- RIGHT COLUMN -->
</div><!-- MAIN CONTAINER -->
</div><!-- WRAPPER -->
</body>
</html>
This is what it looks like:
you can get it working with js:
<script>
$(document).ready(function() {
var height = Math.max($("#left").height(), $("#right").height());
$("#left").height(height);
$("#right").height(height);
});
</script>
I've seen many attempts to do this, though none met my OCD needs. You might need to dedicate a second to get your head around this, though it is better than using JavaScript.
Known downsides:
Does not support multiple element rows in case of a container with dynamic width.
Does not work in IE6.
The base:
red is (auxiliary) container that you would use to set margin to the content.
green is position: relative; overflow: hidden and (optionally, if you want columns to be centered) text-align: center; font-size: 0; line-height: 0;
blue display: block; float: left; or (optionally, if you want columns to be centered) display: inline-block; vertical-align: top;
So far nothing out of ordinary. Whatever content that blue element has, you need to add an absolutely positioned element (yellow; note that the z-index of this element must be lower than the actual content of the blue box) with this element and set top: 0; bottom: 0; (don't set left or right position).
All your elements now have equal height. For most of the layouts, this is already sufficient. My scenario required to have dynamic content followed by a static content, where static content must be on the same line.
To achieve this, you need to add padding-bottom (dark green) eq to the fixed height content to the blue elements.
Then within the yellow elements create another absolutely positioned (left: 0; bottom: 0;) element (dark blue).
Supposedly, if these boxes (yellow) had to be active hyperlinks and you had any style that you wanted to apply to the original blue boxes, you'd use adjacent sibling selector:
yellow:hover + blue {}
Here is a the code and demo:
HTML:
<div id="products">
<ul>
<li class="product a">
<a href="">
<p class="name">Ordinary product description.</p>
<div class="icon-product"></div>
</a>
<p class="name">Ordinary product description.</p>
</li>
<li class="product b">
<a href="">
<p class="name">That lenghty product description or whatever else that does not allow you have fixed height for these elements.</p>
<div class="icon-product"></div>
</a>
<p class="name">That lenghty product description or whatever else that does not allow you have fixed height for these elements.</p>
</li>
<li class="product c">
<a href="">
<p class="name">Another ordinary product description.</p>
<div class="icon-product"></div>
</a>
<p class="name">Another ordinary product description.</p>
</li>
</ul>
</div>
SCSS/LESS:
#products {
ul { position: relative; overflow: hidden; text-align: center; font-size: 0; line-height: 0; padding: 0; margin: 0;
li { display: inline-block; vertical-align: top; width: 130px; padding: 0 0 130px 0; margin: 0; }
}
li {
a { display: block; position: absolute; width: 130px; background: rgba(255,0,0,.5); z-index: 3; top: 0; bottom: 0;
.icon-product { background: #ccc; width: 90px; height: 90px; position: absolute; left: 20px; bottom: 20px; }
.name { opacity: 1; }
}
.name { position: relative; margin: 20px 10px 0; font-size: 14px; line-height: 18px; opacity: 0; }
a:hover {
background: #ddd; text-decoration: none;
.icon-product { background: #333; }
}
}
}
Note, that the demo is using a workaround that involves data-duplication to fix z-index. Alternatively, you could use pointer-events: none and whatever solution for IE.
here is very simple solution with a short css display:table
<div id="main" class="_dt-no-rows">
<div id="aside" contenteditable="true">
Aside
<br>
Here's the aside content
</div>
<div id="content" contenteditable="true">
Content
<br>
geht's pellentesque wurscht elementum semper tellus s'guelt Pfourtz !. gal hopla
<br>
TIP : Just clic on this block to add/remove some text
</div>
</div>
here is css
#main {
display: table;
width: 100%;
}
#aside, #content {
display: table-cell;
padding: 5px;
}
#aside {
background: none repeat scroll 0 0 #333333;
width: 250px;
}
#content {
background: none repeat scroll 0 0 #E69B00;
}
its look like this
Well, I don't do a ton of jQuery, but in the CSS/Javascript world I would just use the object model and write a statement as follows:
if(leftDiv.style.height > rightDive.style.height)
rightDiv.style.height = leftDiv.style.height;
else
leftDiv.style.height = rightDiv.style.height)
There's also a jQuery plugin called equalHeights that I've used with some success.
I'm not sure if the one I'm using is the one from the filament group mentioned above, or if it's this one that was the first google result... Either way a jquery plugin is probably the easiest, most flexible way to go.
Use this in jquery document ready function. Considering there are two divs having ids "left" and "right."
var heightR = $("#right").height();
var heightL = $("#left").height();
if(heightL > heightR){
$("#right").css({ height: heightL});
} else {
$("#left").css({ height: heightR});
}
Although many disagree with using javascript for this type of thing, here is a method that I used to acheive this using javascript alone:
var rightHeight = document.getElementById('right').clientHeight;
var leftHeight = document.getElementById('left').clientHeight;
if (leftHeight > rightHeight) {
document.getElementById('right').style.height=leftHeight+'px';
} else {
document.getElementById('left').style.height=rightHeight+'px';
}
With "left" and "right" being the id's of the two div tags.
This is what I use in plain javascript:
Seems long, but is very uncomplicated!
function equalizeHeights(elements){
//elements as array of elements (obtain like this: [document.getElementById("domElementId"),document.getElementById("anotherDomElementId")]
var heights = [];
for (var i=0;i<elements.length;i++){
heights.push(getElementHeight(elements[i],true));
}
var maxHeight = heights[biggestElementIndex(heights)];
for (var i=0;i<elements.length;i++){
setElementHeight(elements[i],maxHeight,true);
}
}
function getElementHeight(element, isTotalHeight){
// isTotalHeight triggers offsetHeight
//The offsetHeight property is similar to the clientHeight property, but it returns the height including the padding, scrollBar and the border.
//http://stackoverflow.com/questions/15615552/get-div-height-with-plain-javascript
{
isTotalHeight = typeof isTotalHeight !== 'undefined' ? isTotalHeight : true;
}
if (isTotalHeight){
return element.offsetHeight;
}else{
return element.clientHeight;
}
}
function setElementHeight(element,pixelHeight, setAsMinimumHeight){
//setAsMinimumHeight: is set, we define the minimum height, so it can still become higher if things change...
{
setAsMinimumHeight = typeof setAsMinimumHeight !== 'undefined' ? setAsMinimumHeight : false;
}
var heightStr = "" + pixelHeight + "px";
if (setAsMinimumHeight){
element.style.minHeight = heightStr; // pixels
}else{
element.style.height = heightStr; // pixels
}
}
function biggestElementIndex(arr){
//http://stackoverflow.com/questions/11301438/return-index-of-greatest-value-in-an-array
var max = arr[0];
var maxIndex = 0;
for (var i = 1; i < arr.length; i++) {
if (arr[i] > max) {
maxIndex = i;
max = arr[i];
}
}
return maxIndex;
}
I agree with initial answer but the JS solution with equal_heights() method does not work in some situations, imagine you have products next to each other. If you were to apply it only to the parent container yes they will be same height but the product name sections might differ if one does not fit to two line, this is where i would suggest using below
https://jsfiddle.net/0hdtLfy5/3/
function make_children_same_height(element_parent, child_elements) {
for (i = 0; i < child_elements.length; i++) {
var tallest = 0;
var an_element = child_elements[i];
$(element_parent).children(an_element).each(function() {
// using outer height since that includes the border and padding
if(tallest < $(this).outerHeight() ){
tallest = $(this).outerHeight();
}
});
tallest = tallest+1; // some weird shit going on with half a pixel or something in FF and IE9, no time to figure out now, sowwy, hence adding 1 px
$(element_parent).children(an_element).each(function() {
$(this).css('min-height',tallest+'px');
});
}
}

Categories

Resources