We have almost completed the development of our Bootstrap 3 based web site, but where we need to display columns comprising of thumbnails and text they don't always wrap and align correctly. It works on Chrome and Safari, but doesn't work 100% of the time on Firefox, and we have pretty much run out of ideas.
We are using a script from CSS Tricks (http://css-tricks.com/equal-height-blocks-in-rows/) to set the rows to equal height.
The best way to describe what is happening is to let you take a look for yourself. A good example is on this page
Set the view to settings to Show All Products and the Display to Gallery View.
On page load, the script ("columnConform") should set the height of columns with id "page-wrap" to equal the height of the tallest in each row. It doesn't always do this 100%.
If you resize the window, the script will again be triggered, and generally works better this time, although not 100% in Firefox.
The script code for setting equal heights is below (on our site in file thumbnail-row-fix.js):
// these are (ruh-roh) globals. You could wrap in an
// immediately-Invoked Function Expression (IIFE) if you wanted to...
var currentTallest = 0,
currentRowStart = 0,
rowDivs = new Array();
function setConformingHeight(el, newHeight) {
// set the height to something new, but remember the original height in case things change
el.data("originalHeight", (el.data("originalHeight") == undefined) ? (el.height()) : (el.data("originalHeight")));
el.height(newHeight);
}
function getOriginalHeight(el) {
// if the height has changed, send the originalHeight
return (el.data("originalHeight") == undefined) ? (el.height()) : (el.data("originalHeight"));
}
function columnConform() {
// find the tallest DIV in the row, and set the heights of all of the DIVs to match it.
$('#page-wrap > div').each(function() {
// "caching"
var $el = $(this);
var topPosition = $el.position().top;
if (currentRowStart != topPosition) {
// we just came to a new row. Set all the heights on the completed row
for(currentDiv = 0 ; currentDiv < rowDivs.length ; currentDiv++) setConformingHeight(rowDivs[currentDiv], currentTallest);
// set the variables for the new row
rowDivs.length = 0; // empty the array
currentRowStart = topPosition;
currentTallest = getOriginalHeight($el);
rowDivs.push($el);
} else {
// another div on the current row. Add it to the list and check if it's taller
rowDivs.push($el);
currentTallest = (currentTallest < getOriginalHeight($el)) ? (getOriginalHeight($el)) : (currentTallest);
}
// do the last row
for (currentDiv = 0 ; currentDiv < rowDivs.length ; currentDiv++) setConformingHeight(rowDivs[currentDiv], currentTallest);
});
}
$(window).resize(function() {
columnConform();
});
// Dom Ready
// You might also want to wait until window.onload if images are the things that
// are unequalizing the blocks
window.onload = function() {
columnConform();
//$(window).load(function() {
//columnConform();
// setTimeout(function(){columnConform()},6000);
};
Supposedly window.onload or $(window).load are the same and are triggered when the DOM and ALL images have loaded. If so, I can't explain why the script works differently when the page is loaded to when the window is resized in Firefox.
Maybe it's a bug in the latest version of Firefox, but I can't see anything relevant on the forums.
Any thoughts, tips and ways to try and get this working would be much appreciated.
I hope I explained this adequately, displaying the page ought to trigger the problem.
I have (for now) had to give up on finding the ideal solution to this problem, but have managed to find a solution that at least works.
The "columnConform" script works by setting the height of all columns in a row (ie: having the same offset from the top of the page) to the height of the tallest column in the row.
Unfortunately where columns are of sufficient unequal height, they do not output to the page in the correct row, and therefore this script will not fix the problem.
A minor change makes the script think that ALL columns have an offset of 0 from the top of the page, therefore they are ALL in the same row and are all given the height of the tallest.
Provided that there isn't a single column that is a LOT taller than the rest, this is not a problem. On most of our pages fortunately doing this only results in a little more white space between the rows than we wanted to achieve.
The code change is as follows:
// var topPosition = $el.position().top;
var topPosition = 0;
Related
Let me start by saying I have almost no understanding of JavaScript.
I have a Bootstrap (3) carousel, which contains images and text, of different quantities. When the carousel animates, all content below the carousel jumps as the carousel resizes its height according to the height of the content.
I have followed http://ryanringler.com/blog/2014/08/24/fixed-height-carousel-for-twitter-bootstrap which is designed to calculate the maximum height of the content within the carousel, and apply to each slide - preventing the jump of page content below the carousel. This has almost fixed the problem, but not quite.
It seems the javascript only applies after I resize the browser window. Having basically no understanding of how JS works, I was hoping there is a simple solution to this that someone might be able to help me with? I would be eternally greatful!
I have the following loaded in the Page Header Tags section of Page Settings > Advanced Settings in DNN.
window.onload = function() {
carouselNormalization();
}
I have the following loaded within script tags in an html module on the page:
function carouselNormalization() {
var items = $('#carousel-reviews .item'), // grab all the slides
heights = [], // array to store heights
tallest; // tallest slide
if (items.length) {
function normalizeHeights() {
items.each(function() {
heights.push($(this).height()); // add each slide's height
}); // to the array
tallest = Math.max.apply(null, heights); // find the largest height
items.each(function() {
$(this).css('min-height', tallest + 'px'); // set each slide's minimum
}); // height to the largest
};
normalizeHeights();
$(window).on('resize orientationchange', function() {
tallest = 0, heights.length = 0; // reset the variables
items.each(function() {
$(this).css('min-height', '0'); // reset each slide's height
});
normalizeHeights(); // run it again
});
}
}
Here is the page: http://mystate.com.au/about-us/contact-us/locations/launceston-branch
I have also noticed that sometimes the JS does apply if I press the scroll button immediately after page load, but if I wait a few seconds, it seems it doesn't.
Thanks for any help in advance!
The Chrome console says: carouFredSel: No element found for "#carousel_2item" and also for #carousel_4item. You should probably fix that first.
Also the id carousel-id does not exist on your site. You probably need to replace that with the ID of your actual element. (try carousel-reviews)
In Javascript I load some elements via AJAX from a server, and for each data-element I create a <div> that contains another div and an <img>. The inner div contains between 2 and 5 lines of text. I arrange three of this items side by side in a row, then the next three in the next row and so on.
But since the texts have different lengths, I want to do some fine-adjustment of the elements within each row. I want the top-edges of all three images to be on the same height. To do this, I do this:
Insert the three <div><div>text</div><img></div>-blocks into their container.
Get the heights of the three <div>text</div>-elements,
calculate their maximum, and then
set their padding-top properties in a way that gives them all the same height.
In Safari and Chrome this works perfectly fine when I turn on the console and set breakpoints to watch what is going on in detail.
But when I turn off breakpoints in this two browsers, the text-diffs don't get their correct padding-values.
I am pretty sure, that - at breakpoints off - the browser is still working on inserting the three dom-elements and rendering the pictures, when javascript tries to measure the heights of the text-divs. So it measures them at a time when they don't have their final values. The script reads wrong values and so it puts wrong values to the padding-top-property.
This does not happen in all browsers:
When running normally (without console and breakpoints) it works always fine within:
Firefox
Opera
Internet Explorer (running in a virtual Machine on my iMac)
But I have those problems in:
Safari
Chrome
What can I do to ensure, that the measurement of an elements height happens when the rendering-machin has finished its manipulation?
EDIT:
I found out another very important detail:
The problem occurs, because of the height of the text-div above the image. Sometimes the text fits very tightly into two rows. One small letter more in any of the rows and it would be three rows.
In this case my script, that runs immediately after the div was created, measures a height of three lines (60 pixel), and everything would be absolutely correct, if this div did really contain 3 lines of text. My script manipulates the elements in a manner that would be perfect if this div really was 3 lines high.
But obviously, some milliseconds after my script was running, the browser (Safari and Chrome) performs an improvement of font-rendering. And then suddenly the text fits into 2 lines, which makes the text-div only 40 pixels high. And so the image moves up 20 pixels, and this destroys my just processed result (all images was at the same position)
So,does this give you any idea on how to solve the problem? Is there a way to let that part of my script run after all rendering-polishing has finished? Is there an event like onFinishingRenderingImprovementsDone?
(written on May the 4th be with you = Star Wars day)
How about having your script run with a short delay - setTimeout(function() {[your code here]}, 100) (or however long it needs...) - and see if you can simply avoid the problem altogether? Less than a second probably, and for an async action, adding a very short wait would likely not be noticeable.
You can monitor the height of the elements, and when an element height changes, you can recalculate the padding.
Example:
$.fn.changeHeight = function(callback){
return this.each(function(i, e){
var el = $(e), height = el.height();
window.setInterval(function(){
var h = el.height();
if (h != height) {
height = h;
callback.call(e);
}
}, 100);
});
};
function rndText() {
var txt = '';
for (var i = Math.floor(Math.random() * 20); i >= 0; i--) {
txt += 'asdf ';
}
return txt;
}
for (var i = 0; i < 10; i++) {
var d = $('<div>').append(
$('<div>').prop('contenteditable', true).text(rndText()).changeHeight(resize)
).appendTo('body');
}
resize();
function resize() {
console.log('resize');
var height = 0;
$('body > div').each(function(i, e) {
var d = $(e);
var h = d.find('div').height();
if (h > height) height = h;
});
$('body > div').each(function(i, e) {
var d = $(e);
d.css('padding-top', height - d.find('div').height());
});
}
Demo: http://jsfiddle.net/Guffa/Lunxbr6p/2/
The boxes in the demo are editable, so you can change the text and see how the boxes resize.
I have a function that corrects and adapts the size (and vertical alignment) of three fluid columns with text and images.
The script, while not polished/efficient yet, works exactly as expected but sometimes(?) fails at the beginning.
The functions is the following:
var resetHeight = function(){
var maxHeight = 0;
$(".same-height-col").height("auto").each(function(){
maxHeight = $(this).height() > maxHeight ? $(this).height() : maxHeight;
}).height(maxHeight + 25);
var maxTextSize = 0;
var tempHeight;
$(".same-height-col").each(function(){
tempHeight = $(this).find(".links-text").height();
maxTextSize = tempHeight > maxTextSize ? tempHeight : maxTextSize;
});
var topMargin;
$(".same-height-col").each(function(){
topMargin = (maxTextSize - $(this).find(".links-text").height()) + 25;
$(this).find(".links-image").css("margin-top",topMargin);
});
}
The I call it twice:
$(document).ready(function() {
resetHeight();
$(window).resize(function() {
resetHeight();
});
});
The problem is that many times when I load the page, I see this:
That doesn't happen consistently, but it does happen pretty often, but as soon as I resize the window the script works exactly as expected:
So where could the mistake be?
The script is called for sure even at the beginning, if I put an alert in the function, and just load the page (with no resize), the alert pops up.
When you calculate the maxHeight value, you reset all the inline heights that were set in the previous resetHeight call by doing $(".same-height-col").height("auto"). However, you don't reset the margin-top properties that were added to the links-image elements.
This means that the second time that resetHeight is called (and all subsequent times), the maxHeight calculations will be different. To make sure the results are the same each time, you need to reset the margin-top property on the links-image elements before doing the calculation.
$(".same-height-col .links-image").css("margin-top","");
$(".same-height-col").height("auto").each(function(){
maxHeight = $(this).height() > maxHeight ? $(this).height() : maxHeight;
}).height(maxHeight + 25);
You may also want to make that height maxHeight+50 rather than maxHeight+25 if you think the result of the layout after the resize looked better than the intial layout on load.
As i understand your issue, you should set attribute width and height of images and use the document ready handler:
HTML for all images in .links-image DIVs: {width/height/alt attributes should always be specified for image when possible}
<div class="links-image" style="margin-top: 53px;">
<img src="img/list.png" width="210" height="92" alt="">
</div>
JS code:
$(document).ready(function() {
$(window).resize(resetHeight).trigger('resize');
});
I’m starting with the premise that you want the box content components — the title, the subtitle, and the image — vertically aligned across all the three boxes. If this is not true, just ignore this answer.
While I can’t spot the issue in the code at hand, I would try to approach it another way, without JS: clearfix the columns and fix the height of the components: let’s say I expect titles to be one line of text, subtitles three lines, and images are already fixed-height.
The fixed height will give you vertical alignment, and the clearfix will take care of the column height.
I have run into a strange phenomena I believe and I was wonder if anyone has a the answer to why this occurs. I have been doing a lot of manipulation of images for a photography site using a custom jQuery slideshow I created and have run into some problems.
I have a gallery here: http://www.daemondeveloper.com/photography/gallery.php
I have been adding some functions that resize the images in this gallery so that they scale to the size of the preview image size. As you can see, the very last image is panoramic and does not fill up the entire height of the div even though I have javascript telling it to resize.
If you refresh the page, the javascript seems to work all of a sudden and the pictures scales how it should.
Now try clicking on the panoramic picture of the girl and my slideshow will appear displaying the image scaled and centered vertically using jQuery. The function below is what handles clicking on the small image previews in the gallery.
If you look at where the commented changeSize() function is, that is where I USED to have the function and the scaling did not work. Then I moved it after the .show() functions which show my slideshow and now it works. So it appears that the display:none; affected how the javascript fired because when I debugged, the currentImg object was null, as if the .slides selector did not exist when it was set to display:none;. Is this really happening or am I just seeing a side effect of something else?
If this is really happening it may have something to do with the cause of the first problem I stated about the panoramic image not scaling on the first load of the gallery.php page.
$('.imgHolder').click(function(){
currentPosition = $('.imgHolder').index(this);
$('#slideShow').width(slideWidth);
// Remove scrollbar in JS
$('#slideContainer').css('overflow', 'hidden');
// Wrap all .slides with #slideInner div
slides.css({
'float' : 'left',
'width' : slideWidth
});
// Set #slideInner width equal to total width of all slides
$('#slideInner').css('width', (slideWidth * numberOfSlides));
// Hide left arrow control on first load
manageControls(currentPosition);
$('#slideInner').css('margin-left' , slideWidth*(-currentPosition));
//changeSize(); used to be here
$('#filter').show();
$('#photoWrap').show();
//Change image scale and center
changeSize();
});
And here is the changeSize() function that does the scaling and centering
function changeSize(){
currentSlide = $('.slide').get(currentPosition);
currentImg = $(currentSlide).children('img:first')[0];
imgRatio = $(currentImg).height() / $(currentImg).width();
if(imgRatio < slideRatio)
{
$(currentImg).addClass('landscape');
//Vertically align
var thisHeight = $(currentImg).height();
$(currentImg).css('margin-top', ($('#slideShow').height()/2)-(thisHeight/2));
}else{
$(currentImg).addClass('portrait');
}
}
$('#gallery ul li').each(function() {
var img = $(this).children('div').children('img').first();
var ratio = img.height() / img.width();
var goal = img.parent('div').height() / img.parent('div').width();
if (ratio < goal) {
img.addClass('portrait');
img.css('margin-left', -(img.width() / 2) + ($(this).children('div').width() / 2));
} else {
img.css('width', '100%');
}
});
Here I removed the unnecessary $() instances from your code, as you have already selected the element that you wish to call your methods on when you set the img variable. I doubt that this redundancy is the ultimate issue, but it is a good place to start.
Update your code to this and let's debug from there.
EDIT:
I think I found your error (well, I found one at least):
function configGallery()
{
var currentPosition;
var slides = $('.slide')
var currentSlide;
var currentImg;
var slideWidth = 720;
var numberOfSlides = slides.length;
...
}
Do you see what's wrong here? You forgot a semi-colon after var slides = $('.slide') and that could be your issue. Honestly, I'm surprised any of your scripts ran at all. Missing semi-colons usually crash the whole thing.
UPDATE:
Here are a few more selectors for you to remove the $() from when you get a chance:
function changeSize(){
currentSlide = $('.slide').get(currentPosition);
currentImg = $(currentSlide).children('img').first();
imgRatio = $(currentImg).height() / $(currentImg).width();
if(imgRatio < slideRatio)
{
$(currentImg).addClass('landscape');
//Vertically align
var thisHeight = $(currentImg).height();
$(currentImg).css('margin-top', ($('#slideShow').height()/2)-(thisHeight/2));
}else{
$(currentImg).addClass('portrait');
}
}
UPDATE:
Okay I wrote you a little fiddle to help you re-write your image-sizing function. I'll work on prettying it up and putting it in a plugin for you.
UPDATE:
Here's the same function again in a quick and dirty plugin: http://jsfiddle.net/Wj3RM/3/
I didn't pretty it up though - I figured it would be easier for you to adapt and modify like this.
I'm trying to achieve equal height columns on a 'responsive' website.
That means I'm using media queries to provide several layouts for one website depending on the size of the device and window.
I have 2 columns which need to have the same height. It's easy to achieve when the layout is fixed. I found dozens of scripts that do it and it works well.
However when I resize the browser window, that generated height doesn't change. So if the window is smaller, the height of the columns stays the same as before and the contents of the columns overflows. It's ugly.
Is there a way that generated height could change as I resize the window ?
Note : because of what's inside the columns I cannot use any CSS trick with backgrounds images etc. I really REALLY need both columns to truly have the same height at all times.
This question is already pretty old, but I didn't stumble upon a good solution for this myself until now.
A working solution would be a jQuery plugin that does something like setting the height of the columns to 'auto', measuring which one is the highest and set the columns to that height. Something along the lines of this:
$.fn.eqHeights = function (options) {
var $el = $(this),
$window = $(window),
opts = $.extend({}, $.fn.eqHeights.defaults, options);
if ($el.length > 0 && !$el.data('eqHeights')) {
$(window).bind('resize.eqHeights', function () {
$el.eqHeights(opts);
});
$el.data('eqHeights', true);
}
return $el.each(function () {
var children = $(this).find(opts.childrenSelector);
if (!(opts.minWidth) || opts.minWidth < $window.width()) {
var curHighest = 0;
children.each(function () {
var $el = $(this),
elHeight = $el.height('auto').height();
if (elHeight > curHighest) {
curHighest = elHeight;
}
}).height(curHighest);
} else {
children.height('auto');
}
});
};
$.fn.eqHeights.defaults = {
childrenSelector: '*',
minWidth: ''
};
You can see this in action here: demo#codepen.io
The plugin supports two options:
childrenSelector: (Optional) The selector by which children that should get equal height are picked. Defaults to *, so everything in your parent is brought to equal height. Set to > to pick only direct children or something else to get the desired effect.
minWidth: (Optional) The minimum viewport width above width the Plugin is working and calculates equal heights for the seleted children. Below their height is set to auto. This comes in handy if at some point your containers are laid out below each other and shouldn't have an equal height. Empty and inactive by default.
While this is working very good in all browser with which I tested, it is a very hackish solution, so maybe someone here can propose something better. I thought about copying the columns and their wrapper to hidden container in the document, but this isn't any less clean and produces a way bigger footprint.
My favorite trick to creating equal height columns that work almost everywhere is to set "overflow:hidden" on a wrapper div, and setting a huge positive bottom padding and a negative bottom margin on the columns themselves. Now the columns will always be the full height of the wrapper, whatever the height of the wrapper is.
Viz -
<div class="wrapper">
<div class="column"> Column one content </div>
<div class="column"> Column two content </div>
</div>
<style type="text/css">
.wrapper {
overflow:hidden;
}
.column {
margin-bottom: -2000px;
padding-bottom: 2000px;
}
</style>
Here's a JSFiddle example - http://jsfiddle.net/yJYTT/
I wrote a small jQuery plugin for this: http://github.com/jsliang/eqHeight.coffee/
Tested it on Chrome, Firefox and IE9 and it works for me.
This works great! To make it work inside of a responsive layout you'll need to add the # media query so it's only used on screen sizes "larger than" your break point. Otherwise, the sidebar color extends down into the main content on the tablet and phone views. Here's how it looks in a responsive stylesheet:
div.wrapper {
overflow:hidden;
}
.column {
background-color: rgba(193,204,164,.5);
padding:2%;
margin-bottom: -2000px;
padding-bottom: 2000px;
}
#media screen and (max-width:960px){
.column {padding-bottom:2%; margin-bottom:0px;}
}
I hacked the solution even further from boundaryfunctions's answer to take into consideration responsive layouts where the panels reflow above each other.
By checking each one against the first one's offset.top I was able to detect the orientation of the panels and resize their .panel-body element or assign an auto heigh for reflowed panels.
(function($) {
$.fn.eqHeights = function() {
var el = $(this);
if (el.length > 0 && !el.data('eqHeights')) {
$(window).bind('resize.eqHeights', function() {
el.eqHeights();
});
el.data('eqHeights', true);
}
var panels = el.find(".panel-body");
var fistoffset = panels.first().offset();
var curHighest = 0;
return panels.each(function() {
var thisoffset = $(this).offset();
var elHeight = $(this).height('auto').height();
if(thisoffset.top==fistoffset.top){
if (elHeight > curHighest) {
curHighest = elHeight;
}
}else{
curHighest = "auto";
}
}).height(curHighest);
};
}(jQuery));
$('.match_all').eqHeights();
Example here: http://bootply.com/render/104399
Some time after the question I know - but for reference - last time I had to solve this problem I hacked this jquery code to a plugin:
http://css-tricks.com/equal-height-blocks-in-rows/
obviously $(window).resize is the crucial part - as it'll re-conform the heights once the re-size has taken place. Taking it a step further I always meant to look into 'de-bouncing' the column reconform to help with performance:
http://paulirish.com/2009/throttled-smartresize-jquery-event-handler/
but never got that far.
I had the same problem. After some research I selected the faux column technique. Check this blog post that I wrote on how to make it work in a responsive design.
Responsive full height (equal height) columns using the faux columns technique