我正在尝试使用以下代码平衡图片库中列之间的高度:
section {
background: magenta;
/* So you can see the area I don't want to appear */
}
.gallery {
width: 100%;
line-height: 0;
-webkit-column-count: 2;
-webkit-column-gap: 0;
-moz-column-count: 2;
-moz-column-gap: 0;
column-count: 2;
column-gap: 0;
}
<section class="gallery">
<div>
<img src="http://lorempixel.com/800/1000/">
</div>
<div>
<img src="http://lorempixel.com/800/600/">
</div>
<div>
<img src="http://lorempixel.com/800/200/">
</div>
<div>
<img src="http://lorempixel.com/800/700/">
</div>
<div>
<img src="http://lorempixel.com/800/900/">
</div>
<div>
<img src="http://lorempixel.com/800/400/">
</div>
<div>
<img src="http://lorempixel.com/800/200/">
</div>
<div>
<img src="http://lorempixel.com/800/600/">
</div>
<div>
<img src="http://lorempixel.com/800/700/">
</div>
<div>
<img src="http://lorempixel.com/800/600/">
</div>
<div>
<img src="http://lorempixel.com/800/550/">
</div>
<div>
<img src="http://lorempixel.com/800/700/">
</div>
<div>
<img src="http://lorempixel.com/800/600/">
</div>
<div>
<img src="http://lorempixel.com/800/1000/">
</div>
<div>
<img src="http://lorempixel.com/800/700/">
</div>
</section>
这是一个JSFiddle:https://jsfiddle.net/auan2xnj/1/
图片都具有不同的高度,但都具有相同的宽度。我的column-fill
设置为balance
(默认情况下)。
在JSFiddle中,它看起来相当不错,但在我正在开发的网站上,比较列的高度出现了一些巨大的差距。我猜这是因为图像在HTML中的顺序,考虑到它们将被CSS放入列中的完全相同的顺序。这是我的项目的截图,使用与JSFiddle完全相同的代码:
当我为.gallery
元素提供硬编码的height
值时,列始终平衡得更好。这是一个问题,因为在我的网站中,图像是动态添加的,我永远不会知道所有画廊的确切高度。
我想找到一段代码(无论是什么,我认为我可以实现一些JS)来修复这个问题,或者通过重新排序HTML中的图像,以便结果是最好的,或者无论如何为了动态设置高度,以解决问题。
答案 0 :(得分:9)
编辑:
如果您不需要保留line-height: 0
,则只需使用.gallery img {display:block}
并删除行高,这就是您所需要的一切。那将是最好的。 table-cell
等可能会产生一些副作用。例如vertical-align: middle
在图像下留下一个空间,而且只是一个黑客。
https://jsfiddle.net/bruLwktv/
Challange接受了,这是解决方案:;)
该算法确保每个图像都被加载,然后将它们分成两个颜色,使得最接近的总高度可以创建最小的间隙。
使用The greedy algorithm分区问题创建平衡分区。
var gallery = document.getElementsByClassName("gallery")[0]
var images = gallery.getElementsByTagName("img")
var notLoaded = 0
window.onload = function() {
for (var i = images.length; i--;) {
if (images[i].width == 0) {
// let the image tell us when its loaded
notLoaded++
images[i].onload = function() {
if (--notLoaded == 0) {
allImgLoaded()
}
}
}
}
// check if all images are already loaded
if (notLoaded == 0) allImgLoaded()
}
function allImgLoaded() {
// Partition images
var imgs = partitionImages(images)
// reorder DOM
for (var i = images.length; i--;) {
gallery.appendChild(imgs[i])
}
}
function partitionImages(images) {
var groupA = [], totalA = 0
var groupB = [], totalB = 0
// new array width img and height
var imgs = []
for (var i = images.length; i--;) {
imgs.push([images[i], images[i].height])
}
// sort asc
imgs.sort(function(a, b) {
return b[1] - a[1]
});
// reverse loop
for (var i = imgs.length; i--;) {
if (totalA < totalB) {
groupA.push(imgs[i][0])
totalA += imgs[i][1]
} else {
groupB.push(imgs[i][0])
totalB += imgs[i][1]
}
}
return groupA.concat(groupB)
}
section {
background: magenta;
/* So you can see the area I don't want to appear */
}
.gallery {
width: 100%;
line-height: 0;
-webkit-column-count: 2;
-webkit-column-gap: 0;
-moz-column-count: 2;
-moz-column-gap: 0;
column-count: 2;
column-gap: 0;
}
<section class="gallery">
<div><img src="http://lorempixel.com/800/1000/"></div>
<div><img src="http://lorempixel.com/800/600/"></div>
<div><img src="http://lorempixel.com/800/200/"></div>
<div><img src="http://lorempixel.com/800/700/"></div>
<div><img src="http://lorempixel.com/800/900/"></div>
<div><img src="http://lorempixel.com/800/400/"></div>
<div><img src="http://lorempixel.com/800/200/"></div>
<div><img src="http://lorempixel.com/800/600/"></div>
<div><img src="http://lorempixel.com/800/700/"></div>
<div><img src="http://lorempixel.com/800/600/"></div>
<div><img src="http://lorempixel.com/800/550/"></div>
<div><img src="http://lorempixel.com/800/700/"></div>
<div><img src="http://lorempixel.com/800/600/"></div>
<div><img src="http://lorempixel.com/800/1000/"></div>
<div><img src="http://lorempixel.com/800/700/"></div>
</section>
答案 1 :(得分:3)
是的,列实现现在很奇怪。
如果你摆脱“line-height:0;”这个问题变得不那么严重了。我不知道为什么。除了说行高的东西是一个黑客去除图像底部无处不在的小空间/边距(如果你不知道我在说什么,删除jfiddle中的行间距规则)
据说空间/边距是存在的,因为HTML不知道img元素不是文本,因此为“y”和“g”等字符的“尾部”留下了空间。这是一个荒谬的错误,我认为应该在十年前修复过。对我来说,这是IE&lt; 9级别的愚蠢实现。
无论如何,咆哮,一种方法来修复空间/边距而不使用行高hack:
img {
vertical-align: middle;
}
此外,如果你肯定所有的图像都是相同的宽度,这不是一个问题,但在小提琴中,通过重叠列的宽度的图像使间隙问题变得更糟。你应该设置
img {
width: 100%
// and, for insurance, I also add:
height: auto;
}
确保您将图像拟合到列中。
答案 2 :(得分:1)
我已经为div {
-webkit-margin-before: 0;
-webkit-margin-after: 0;
}
元素添加了一些CSS,如果有效,请告诉我:
https://jsfiddle.net/rplittle/auan2xnj/3/
我也见过这个:
{{1}}
(必要时调整/添加前缀)
或者您可以尝试Masonry,它构建良好且易于设置。
答案 3 :(得分:1)
请求:强>
我想找到一段代码(无论它是什么,我认为我可以实现&gt;&gt;某些JS)来解决这个问题,或者通过重新排序HTML中的图像来实现&gt;&gt;结果是最好的,或者以任何方式动态设置高度以便解决问题。
贪婪算法是一种很好的方法,对于必须动态扩展切片的流非常有用。 (像分页一样)
我已经添加了一个功能,通过对项目进行分组并在组之间切换项目来实现更好的平衡。
这里的列是通过创建2个内联块和50%宽度的div来实现的;简单,适用于所有现代浏览器。
function balance(numGroups, items, fetchValue){
function delta(a, b){
var da = a-avg, db = b-avg;
return da*da + db*db;
}
function testAndSwitchItems(a,b){
var valueA, valueB,
lengthA = a.length, lengthB = b.length,
indexA = lengthA, indexB = lengthB,
bestDelta = delta(a.sum, b.sum);
//test every item in this first column against every value in the second column
for(var i = 0; i <= lengthA; ++i){
//accessing a not available index of an Array may deoptimize this function
//that's why i check the index before accessing the element.
valueA = (i < lengthA && a[i] || nullElement).value;
for(var j = 0; j <= lengthB; ++j){
valueB = (j < lengthB && b[j] || nullElement).value;
//test wether it would be an improvement to switch these items
var d = delta(
a.sum + valueB - valueA,
b.sum + valueA - valueB
);
//find the best combination
if(d < bestDelta){
indexA = i;
indexB = j;
bestDelta = d;
}
}
}
var elmA = indexA < lengthA && a[indexA],
elmB = indexB < lengthB && b[indexB],
tmp;
if(elmA && elmB){
//switch items
a[indexA] = elmB;
b[indexB] = elmA;
}else if(elmA){
//move an item from a to b
b.push(elmA);
tmp = a.pop()
if(elmA !== tmp)
a[indexA] = tmp;
}else if(elmB){
//move an item from b to a
a.push(elmB);
tmp = b.pop()
if(elmB !== tmp)
b[indexB] = tmp;
}else{
//no switch would improve the result
return false;
}
//compute the new sums per group
valueA = (elmA || nullElement).value;
valueB = (elmB || nullElement).value;
a.sum += valueB - valueA;
b.sum += valueA - valueB;
return true;
}
function initGroupsAndReturnSum(sum, item, i){
var value = fetchValue? fetchValue(item): item;
//distribute the items
if(i<numGroups){
var group = groups[i] = [];
group.sum = value;
}else{
group = groups[ i%numGroups ];
group.sum += value;
}
group.push({
index: i,
value: value
});
return sum + value;
}
var groups = [],
nullElement = { value: 0 },
//don't care wether items is an Array, a nodeList or a jQuery-object/list, ...
avg = groups.reduce.call(items, initGroupsAndReturnSum, 0) / groups.length;
//start switching items between the groups
do {
for(var i=1, done = true; i<groups.length; ++i)
for(var j=0; j<i; ++j)
//test each combination of groups
if(testAndSwitchItems(groups[j], groups[i])){
//this switch may have affected the computation against other groups
//do another loop
done = false;
}
}while(!done);
function sorter(a,b){
return a.index - b.index
}
function getItem(item){
return items[item.index]
}
return groups.map(function(a){
return a.sort(sorter).map(getItem)
});
}
以及使用它的可能方式
var groups = balance(2, //num columns
//something Arraylike that contains some objects to be grouped
document.querySelectorAll('img'),
//a function to compute a value out of an Array-item
img => img.naturalHeight / img.naturalWidth
);
https://jsfiddle.net/77o3ptk2/2/
仅仅为了它,该示例还包括一些样式,如图像周围的填充和枚举,以显示数组已被洗牌的程度。
答案 4 :(得分:0)
您可以使用此http://brm.io/jquery-match-height/来均衡每列的高度。而且它在移动响应方面也很出色。不需要css,只需添加库并放置此代码段
$(function() {
$('.gallery').find('div').matchHeight(options);
});