Подтвердить что ты не робот

Балансировка высоты в столбцах столбцов столбцов, содержащих только изображения

Я пытаюсь сбалансировать высоту между столбцами в галерее изображений, которую я сделал, со следующим кодом:

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>
4b9b3361

Ответ 1

EDIT: Если вам не нужно сохранять line-height: 0, вы просто используете .gallery img {display:block} и удаляете высоту строки, это все, что вам нужно. Это было бы лучше. table-cell и т.д. могут иметь некоторые побочные эффекты. Например, vertical-align: middle оставить пробел под изображениями и просто взломать.

https://jsfiddle.net/bruLwktv/


Challange принят, вот решение:;)

Алгоритм гарантирует, что загружаются все изображения, а затем разделяйте их на оба столбца таким образом, чтобы иметь о ближайшей общей высоте, чтобы создать минимальный пробел.

Использование Жадный алгоритм для проблемы раздела для создания сбалансированных разделов.

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>

Ответ 2

Да, реализация колонок сейчас странная.

Если вы избавитесь от "line-height: 0;" эта проблема становится гораздо менее серьезной. Понятия не имею почему. Если не сказать, что строка-высота - это взломать, чтобы избавиться от этого вездесущего небольшого пространства/поля в нижней части изображения (удалите правило межстрочного интервала в jfiddle, если вы не знаете, о чем я говорю).

Предположительно, что пространство/маржа существует, потому что HTML не знает, что элемент img не является текстом, и поэтому оставляет место для "хвостов" таких символов, как "y" и "g", которые идут ниже строки. Это смехотворная ошибка, которая, я думаю, должна была быть исправлена ​​десять лет назад. Для меня это связано с IE и 9 уровнями глупой реализации.

В любом случае, rant over, способ исправить это пространство/поле без использования взлома строки:

img {
    vertical-align: middle;
}

Кроме того, это не проблема, если вы уверены, что все ваши изображения будут иметь одинаковую ширину, но в скрипте проблема с зазором усугубляется изображениями, перекрывающими ширины столбцов. Вы должны установить

img {
    width: 100%
    // and, for insurance, I also add:
    height: auto;
}

чтобы вы соответствовали изображениям в столбцах.

Ответ 3

Я добавил CSS в элементы <div>, сообщите мне, если это работает:

https://jsfiddle.net/rplittle/auan2xnj/3/

Я также видел это:

div {
  -webkit-margin-before: 0;
  -webkit-margin-after: 0;
}

(при необходимости скопируйте/добавьте префиксы)

Или вы можете попробовать Masonry, он хорошо проработан и довольно прост в настройке.

Ответ 4

Запрос:

     

Я хотел бы найти фрагмент кода (что бы это ни было, я думаю, что я могу реализовать → некоторый JS), который исправляет эту проблему, либо путем переупорядочения изображений в HTML, так и → , чтобы результат был наилучшим, или любым другим способом, чтобы динамически установить высоту, чтобы проблема была решена.

жадный алгоритм - хороший подход и полезен для потоков, где вам нужно динамически расширять фрагменты. (например, разбивка на страницы)

Я включил функцию, которая лучше балансирует, группируя элементы и переключая элементы между группами.

Колонки здесь реализованы путем создания 2 разделов, которые являются встроенными блоками и 50% шириной; простой и работает во всех современных браузерах.

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 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/

Просто ради этого пример также включает в себя еще несколько стилей, таких как прокладка вокруг изображений и перечисление, чтобы показать, насколько массив был перетасован.

Ответ 5

Вы можете выравнивать высоту каждого столбца, используя http://brm.io/jquery-match-height/. И это также хорошо подходит для мобильных устройств. Нет необходимости в css, просто добавьте библиотеку и поставьте этот фрагмент

$(function() {
    $('.gallery').find('div').matchHeight(options);
});