How can i animate a window carousel menu? - javascript

i've been looking around a lot on how to do different carousels, but i'm struggling to find a resource that teaches me what it actually does instead of just throwing code at me. Time wasted on misleading videos where you have to download their special script at the end! :-(
i want to understand it first in vanilla JS/Css first, and then work towards understanding Pug/Scss.
i have the below:
.MenuContainer {
position: relative;
width: 300px;
height: 175px;
background-color: black;
border-radius: 10px;
}
.Imagebox {
height: 150px;
margin-top: 15px;
margin-bottom: 27px;
bottom: -17px;
width: 260px;
margin-left: 20px;
margin-right: 15px;
background-color: lavender;
align-self: center;
position: absolute;
border-radius: 5px;
}
.ListReel {
position: inherit;
height: 120px;
background-color: white;
width: 217px;
bottom: 8px;
margin-left: 20px;
display: flex;
flex-direction: row;
overflow-x: hidden;
justify-content: space-evenly;
}
.fa-chevron-left {
position: inherit;
left: 30px;
bottom: 93px;
font-size: 1.5em;
}
.fa-chevron-right {
position: inherit;
left: 236px;
bottom: 93px;
font-size: 1.5em;
}
.MenuItem {
position: inherit;
height: 85px;
width: 85px;
top: 1px;
position: inherit;
border-color: lawngreen;
border-style: solid;
border-width: 1px;
display: table-row;
}
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://kit.fontawesome.com/a427ef628d.js" crossorigin="anonymous"></script>
<script src="../Scripts/JQuery"></script>
<script src="../Scripts/jquery-ui.min.js"></script>
<link rel="stylesheet" href="../Scripts/jquery-ui.min.css">
<link rel="stylesheet" href="Test.css">
<title>TESTING</title>
</head>
<body>
<h1>Hello!</h1>
<div class="MenuContainer">
<h5 style="text-align: center; margin-top: 5px; color: white;">Select Item</h5>
<div class="Imagebox"></div>
<ul class=ListReel>
<li class="MenuItem"></li>
<li class="MenuItem"></li>
<li class="MenuItem"></li>
<li class="MenuItem"></li>
<li class="MenuItem"></li>
<li class="MenuItem"></li>
</ul>
<i class="fas fa-chevron-left"></i>
<i class="fas fa-chevron-right"></i>
</div>
</body>
</html>
I tried going my own way but i'm completely stuck - i envision that the green boxes will need to be spaced evenly, and in a straight row, the items that fall outside the box, won't be visisble and the scroll will cycle the items "Carousel" style..
Ive tried a lot of things so far and i cant even seem to be able to flex my container/green boxes across let alone make a start on the animation!
Does anyone have any tips or resources or code ideas that can point me in the correct direction? preferably well explained tutorials? please?
Many Thanks

Let's start by thinking what the carousel should do. It should roll new images / items from the sides of the viewing container, right?
This means we want our carousel items to be full width of the carousel container, so the items fill the container and rest are left hanging out. Now we don't want to see the other carousel items outside the carousel and for that we can use overflow: hidden on the carousel container. This CSS declaration means that everything that doesn't fit inside the carousel container is hidden.
The other crucial thing is to lay out the carousel items next to eachother, so that when we move them they appear from the sides.
There are of course multiple ways to achieve this but here's what I would've done.
<div class="carousel">
<div id="carousel-item-wrapper">
<div style="background-color: red" class="carousel-item"></div>
<div style="background-color: blue" class="carousel-item"></div>
<div style="background-color: yellow" class="carousel-item"></div>
</div>
</div>
We have a container for the carousel (class: carousel) and the items within it (class carousel-item). Here I have added also a "carousel-item-wrapper" element here. Its job is to contain all the carousel items so we can just slide this bad boy around and the displayed carousel item will change.
Now for the CSS of this mf.
.carousel {
width: 600px;
height: 200px;
border: 3px solid #333;
overflow: hidden;
}
#carousel-item-wrapper {
display: flex;
flex-direction: row;
position: relative;
left: 0;
transition: left 0.5s;
}
.carousel-item {
display: inline-block;
min-width: 600px;
height: 200px;
}
Let's start with .carousel and .carousel-item.
We set defined width and height attributes for the carousel container according to our needs. We want the same width and height to be applied to carousel-item so they fill the carousel window. We also want to set the aforementioned overflow: hidden on the .carousel container so the other items are not displayed when they don't need to.
Now I have set the width of the carousel items with min-width: 600px. The reason is that the carousel-item-wrapper where we have the items uses flexbox layout display: flex. If the items don't have a min-width attribute set, the flexbox would shrink all of them until they all fit side by side inside the carousel container. We don't want that!
Now we get to talk about the mystical #carousel-item-wrapper element. Firstly, it has flex properties needed for horizontal layout: display: flex to actually use flexbox and flex-direction: row (which is default actually..) which tells flexbox to align the items next to eachother.
Then I have set the wrapper element position to relative which means that if no other settings (left, right, top, bottom) is set the element will be where it would naturally go. The reasoning for relative positioning is that we can then change the left (or right) value to move the long horizontal list of carousel items so that the element we want will be aligned with the .carousel element (the "display window" so to speak).
Lastly, it has transitition: left 0.5s which tells the browser that any time the left attribute is changed (usually by JS), the browser will animate the change of the value. That is, if we first have left: 0px and change it to left: -600px (sliding the carousel one item over, as my carousel has width of 600px) the change will be animated (0.5s refers to the time you want it to take)
Now we have all of the HTML and CSS set up and if you change the left property of #carousel-item-wrapper it will move and animate the carousel.
Only thing we need is to create some JS to move it around. I have opted for a button which just moves the carousel one item.
I wasn't going to explain the JS but seeing that this answer got so long, I might as well do that as well.
function moveCarousel() {
const carouselWrapper = document.getElementById("carousel-item-wrapper");
let left = carouselWrapper.style.left.slice(0, -2);
left = (left - 600) % 1800;
carouselWrapper.style.left = left + 'px';
}
First we start by getting a reference to the wrapper element with document.getElementById. We can use this to read the current value of left attribute on the element and change it. carouselWrapper.style.left is the value of the left property and slice(0, -2), well you can read up on it on your own but here it just strips the "px" from the value (because the value of left is a string of <value>px. Next we want to subtract carousel width from this (so the items slide up correctly). I also used the modulo operator, which is just remainder division. This will mean that once I have subtracted too much, it will wrap over. Now the only thing left is to apply this new value of left to the wrapper.
All in all the implementation would look a bit like this:
(EDIT: I change height to be 100px instead of 200px to make it fit inside the run code snippet window)
function moveCarousel() {
const carouselWrapper = document.getElementById("carousel-item-wrapper");
let left = carouselWrapper.style.left.slice(0, -2);
left = (left - 600) % 1800;
carouselWrapper.style.left = left + 'px';
}
.carousel {
width: 600px;
height: 100px;
border: 3px solid #333;
overflow: hidden;
}
#carousel-item-wrapper {
display: flex;
flex-direction: row;
position: relative;
left: 0;
transition: left 0.5s;
}
.carousel-item {
display: inline-block;
min-width: 600px;
height: 100px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="style.css" rel="stylesheet">
<title>Document</title>
</head>
<body>
<div class="carousel">
<div id="carousel-item-wrapper">
<div style="background-color: red" class="carousel-item"></div>
<div style="background-color: blue" class="carousel-item"></div>
<div style="background-color: yellow" class="carousel-item"></div>
</div>
</div>
<button role="button" onclick="moveCarousel()">Move carousel</button>
</body>
</html>

One quick thing before I answer your question: try and post Minimum Working Examples (MWEs) on stackoverflow, because a) this will make your answer more useful to others; b) because it will help you isolate and debug. To go from full website to MWE, remove stuff until only the problem remains, and none of the other stuff.
Now:
I'm not sure whether you understand the implications of display:flex on .ListReel. This is a flexbox, a web technology that allows simplified formatting of things, and you may have seen it around a few tutorials. But flexbox setups require a bit more than just display:flex. You can read more here: CSS-Tricks post on Flexbox (not mine but i regularly use it)
For starters, try adding flex: 0 0 100% to your .MenuItem, which tells the browser that you want your carousel menu items to take up 100% of the width of the .ListReel. Then, for the moment, set overflow-x to auto, which will show the scrollbar.
Later you might not want the scrollbar; so you can set overflow-x back to hidden. I will assume that you know some javascript - the next step would be to add some javascript to make it work:
<script>
function moveTheListItems(){
var listReel = document.getElementsByClassName("ListReel")[0]; // get a reference to the listReel
listReel.scrollBy(listReel.clientWidth,0); // scroll it to reveal the next frame
}
setInterval(moveTheListItems,500); // run this function every 500ms = half a second
</script>
Hope it helps!

Related

Stack of slides continuously growing

Let us say I want to design a website with four slides. I would like each slide to cover the previous one while the visitor is scrolling. Following is an attempt with stellar.js (a jquery plugin): http://jsfiddle.net/8mxugjqe/. You can see that it works for the first slide, which gets covered by the second one, but I could not have it work for the others.
HTML:
<body>
<div id="one" data-stellar-ratio=".2">
<p>This is the first div.</p>
</div>
<div id="two" data-stellar-ratio="1">
<p>This is the second one.</p>
</div>
<div id="three">
<p>Third one!</p>
</div>
<div id="four">
<p>Fourth and last.</p>
</div>
</body>
CSS:
* {
margin: 0;
padding: 0;
}
#one, #two, #three, #four {
position: absolute;
height: 100%;
width: 100%;
font-size: 5em;
}
p {
margin: 1em;
width: 60%;
}
#one {
background: red;
}
#two {
background: blue;
top: 100%;
}
#three {
background: green;
top: 200%;
}
#four {
background: yellow;
top: 300%;
}
I was able to throw something together using just jQuery and no other libraries. It relies on relative positioning. Basically, everything scrolls normally until one of the slides reaches the top of the browser window. Once it tries to scroll past the top of the browser window, I add an offset to the slide's vertical position to keep it from moving up any further. When scrolling back the other way, I simply subtract from this offset until it hits 0 at which point it begins to scroll normally again.
I'm sure the code can be cleaned up but I added a ton of comments so hopefully it's readable. If you have any questions or you would like me to modify it to better suit your needs, let me know. Here's a fiddle with the solution I came up with:
http://jsfiddle.net/jwnace/jhxfe2gg/
You can also see a full page demo of the same code here:
http://joenace.com/slides/

"float" a DIV to bottom of parent DIV not working. (Using Pos: rel, Bottom 0 etc)

Trying to get a DIV to "float" to the bottom of the div its in. I've got the position set to relative on the parent div and kid, and bottom to 0 on the kid; but it still just sits at the top in the middle.
Parent DIV:
.detailsContainer
{
width: 100%;
height: 30%;
overflow: hidden;
position: relative;
background-color: blue;
}
Kid DIV
.obutton
{
text-align: center;
font-weight: bold;
width: 80%;
height: 29px;
background:rgba(204,204,204,0);
position:relative;
bottom: 0;
display: inline-block;
color: #666;
}
Current actual setup:
<div class="detailsContainer">
<a href="javascript:unhide(\'BookDetails'.$row->BookID.'\');">
<div class="detailview"><b>Book Details<br></a></div>
<div id="BookDetails'.$row->BookID.'" class="hidden">
<table>
<tr><td>Total Stock </td><td>'.$row->TotalStock.'</td>
<td>Current Stock</td><td>'.$row->CurrentStock.'</td></tr>
<tr><td>Awards </td><td>'.$row->Awards.'</td>
<td>Film</td><td>'.$row->Film.'</td></tr>
</table>
</div>
';?>
<br><center><a href = "javascript:void(0)"
onclick = "document.getElementById('light').style.display='block';document.getElementById('fade').style.display='block'">
<div class= "obutton feature2">Reserve Book</div></a></center>
<div id="light2" class="white_content"></div>
<div id="fade" class="black_overlay"></div>
</div>
Its kind of a lot to post for this, but want to make sure nothing is interfering that you guys might spot. It jumps out of php near the bottom, I'll post the entire article if you think the issue might be else where.
I tried to make a jsfiddle of it, but there is so much php and variables that by time I gutted it, it'd just be 2 normal divs, having lost its uniqueness and the issue will probably have been deleted.
Thanks -Tom
.obutton position needs to be absolute... for bottom to work the way you're intending.

Fixed and relative elements within a div

I'm trying to position a fixed element WITHIN a div (not the whole page) in my website.
I want the navigation (deadspin, gawer, awl, other) to be fixed within the writing section so that even when user scrolls, the nav is still there. But currently it's fixed for the whole page.
As you can see on my test page, the navigation is fixed the way I want it to be.
I tried messing around with position:relative/position:fixed for the #small-box-links but that doesn't help.
.home_writing {
display: block;
position: relative;
background: rgba(50, 50, 50, 0);
height: 1000px;
text-align: left;
}
#small-box-container {
border: 1px solid black;
background: rgba(10, 200, 10, 0);
width: 980px;
height: 800px;
overflow: auto;
}
#small-box-links {
position: relative;
margin-left: 700px;
height: 25px;
margin-top: 10px;
}
<div id="small-box-container">
<div id="small-box-links">
deadspin |
gawker |
the awl |
other
</div>
<div style='overflow:hidden; width:980px;'>
<div style='overflow:scroll; width:988px'>
<div id="small-box1" class="small-box">
<h2>deadspin</h2>
<h3>How Pat Summitt Ruined The Best Thing About Women's Basketball</h3>
<!-- etc. for other boxes -->
I found this related question and yet when I try top / left, etc., the element is still fixed to the page, not writing div. (I tried making the parent element, .home_writing, relative but this doesn't fix my issue.)
(On another note, I can't figure out why my Playfair in the paragraphs doesn't look like the sidebar navigation. It's styled the same way).
position:fixed always uses the viewport as the frame of reference, so you can’t use that here.
But the solution is rather simple - use position:absolute instead to position the navigation inside a container element that has position:relative (and a fixed height), and then have the content as a sibling inside that container as well, with fixed height and overflow:auto for that element:
<div style="position:relative; height:800px;">
<div style="position:absolute; top:0; …"> [link link link] </div>
<div style="height:800px; overflow:auto;">
Lorem ipsum, dolor sit …
</div>
</div>

Position badge over corner of image automatically

I have a layout where images "float" within a certain area. The layout looks like this:
The source like this:
<div class="free_tile">
<a class="img_container canonical" href="/photos/10">
<img class="canonical" src="http://s3.amazonaws.com/t4e-development/photos/1/10/andrew_burleson_10_tile.jpg?1303238025" alt="Andrew_burleson_10_tile">
<!-- EDIT: I am aware that I can put the badge here. See the edit notes and image below. -->
</a>
<div class="location">Houston</div>
<div class="taxonomy"> T6 | Conduit | Infrastructure </div>
</div>
The CSS looks like this (in SCSS):
div.free_tile { width: 176px; height: 206px; float: left; margin: 0 20px 20px 0; position: relative;
&.last { margin: 0 0 20px 0; }
a.img_container { display: block; width: 176px; height: 158px; text-align: center; line-height: 156px; margin-bottom: 10px; }
img { margin: 0; border: 1px solid $dark3; display: inline-block; vertical-align: middle; #include boxShadow;
&.canonical { border: 1px solid $transect; }
}
.location, .taxonomy { width: 176px; }
.location { font-weight: 700; }
.taxonomy { line-height: 10px; font-size: 10px; text-transform: uppercase; height: 20px; overflow: hidden; }
}
div.transect_badge { height: 20px; width: 20px; background: url('/images/transect-badge.png'); }
So, basically the images are sitting vertically-aligned middle and text-aligned center, and they have a maximum width of 176 and max height of 158, but they're cropped to maintain the original aspect ratio so the actual top corner of each image falls differently depending on which image it is.
I have a badge that I'd like to put in the top corner of certain images (when the image is "canonical"). You see the style for this above (div.transect_badge).
The problem, of course, is I don't know where the top corner of the image will be so I can't hardcode the position via CSS.
I assume that I'll need to do this via jQuery or something. So, I started with a jQuery method to automatically append the badge div to any canonical images. That works fine, but I can't figure out how to position it over the top left corner.
How can this be done? (ideally using just HTML and CSS, but realistically using JS/jQuery)
--EDIT--
Here's the problem: The image is floating inside a container, so the corner of the image might fall anywhere inside the outer limits of the container. Here's an example of what happens if I try to use position:absolute; top:0; left:0 inside the same container the image is bound by:
It took some tryouts, but here it is: the size independent image badge positioner.
HTML:
<div class="tile">
<span class="photo">
<img src="/photos/10.jpg" alt="10" /><ins></ins>
</span>
<p class="location">Houston</p>
<p class="taxonomy">T6 | Conduit | Infrastructure</p>
</div>
CSS:
.tile {
float: left;
width: 176px;
height: 206px;
margin: 0 20px 20px 0;
}
.photo {
display: block;
width: 176px;
height: 158px;
text-align: center;
line-height: 158px;
margin-bottom: 10px;
}
a {
display: inline-block;
position: relative;
line-height: 0;
}
img {
border: none;
vertical-align: middle;
}
ins {
background: url('/images/badge.png') no-repeat 0 0;
position: absolute;
left: 0;
top: 0;
width: 20px;
height: 20px;
}
Example:
In previous less successful attempts (see edit history), the problem was getting the image vertically centered ánd to get its parent the same size (in order to position the badge in the top-left of that parent). As inline element that parent doesn't care about the height of its contents and thus remains to small, but as block element it stretches to hís parent's size and thus got to high, see demonstration fiddle. The trick seems to be to give that parent a very small line-height (e.g. 0) and display it as an inline-block. That way the parent will grow according to its childs.
Tested in Opera 11, Chrome 11, IE8, IE9, FF4 and Safari 5 with all DTD's. IE7 fails, but a center-top alignment of the photo with badge at the right position isn't that bad at all. Works also for IE7 now because I deleted the spaces in the markup within the a tag. Haha, how weird!
EDIT3: This solution is very similar to my original solution. I didn't really look at your code much so I should have noticed this earlier. Your a tag is already wrapping each image so you can just add the badge in there and position it absolute. The a tag doesn't need width/height. Also you must add the badge image at the beginning of your a tag.
Demo: http://jsfiddle.net/wdm954/czxj2/1/
div.free_tile {
width: 176px;
height: 206px;
float: left;
}
a.img_container {
display: block;
margin-bottom: 10px;
}
span.transect_badge {
display:block;
position: absolute;
height: 20px;
width: 20px;
background-image: url('/images/transect-badge.png');
}
HTML...
<a class="img_container canonical" href="/photos/10">
<span class="transect_badge"></span>
<img class="canonical" src="path/to/img" />
</a>
Other solutions...
In my code I'm using SPAN tags so simulate images, but it's the same idea. The badge image, when positioned absolute, will create the desired effect.
Demo: http://jsfiddle.net/wdm954/62faE/
EDIT: In the case that you need jQuery to position. This should work (where .box is your container and .corner is the badge image)...
$('.box').each(function() {
$(this).find('.corner')
.css('margin-top', ( $(this).width() - $(this).find('.img').width() ) / 2);
$(this).find('.corner')
.css('margin-left', ( $(this).height() - $(this).find('.img').height() ) / 2);
});
EDIT2: Another solution would be to wrap each image with a new container. You would have to move the code that you use to center each image to the class of the new wrapping container.
Demo: http://jsfiddle.net/wdm954/62faE/1/
$('.img').wrap('<span class="imgwrap" />');
$('.imgwrap').prepend('<span class="badge" />');
Technically you can just add something like this to your HTML though without using jQuery to insert it.
Use an element other than <div>, e.g. <span> and put it inside your <a> element after the <img> element. Then, give the <a> element position:relative; and the <span> gets position:absolute; top:0px; left:0px;. That is, if you don't mind the badge also being part of the same link - but it's the easiest way. Also, the reason for using <span> is to keep your HTML4 valid, <div> would still be HTML5 valid, however.
I did find one solution using jQuery. I don't prefer this because it noticably impacts page loading, but it is acceptable if nothing else will work. I'm more interested in NGLN's idea which seems promising but I haven't entirely figured out yet. However, since this thread has picked up a lot of traffic I thought I'd post one solution that I came up with for future readers to consider:
Given this markup:
<div class="free_tile">
<a class="img_container canonical" href="/photos/10">
<img class="canonical" src="http://s3.amazonaws.com/t4e-development/photos/1/10/andrew_burleson_10_tile.jpg?1303238025" alt="Andrew_burleson_10_tile">
<span class="transect-badge"></span>
</a>
<div class="location">Houston</div>
<div class="taxonomy"> T6 | Conduit | Infrastructure </div>
</div>
Same CSS as in question except:
span.transect-badge { display: block; height: 20px; width: 20px; position: absolute; background: url('/images/transect-badge.png'); }
Then this jQuery solves the problem:
$(function() {
$('img.canonical').load( function() {
var position = $(this).position();
$(this).next().css({ 'top': position.top+1, 'left': position.left+1 });
});
});
Like I said, though, this incurs noticeable run-time on the client end, so I'd prefer to use a non JS solution if I can. I'll continue to leave this question open while I test out and give feedback on the other solutions offered, with hopes of finding one of them workable without JS.

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