我正在使用同位素js https://isotope.metafizzy.co/并且无法理解如何使我的布局具有平底,如下所示https://diefinnhutte.qodeinteractive.com/masonry-portfolio/ 。 我无法为我的块设置固定高度,但在上面的示例中,我认为同位素给出了自己的高度。
如何制作?
我有简单的代码:
<div class="grid">
<div class="grid-item">...</div>
<div class="grid-item">...</div>
<div class="grid-item">...</div>
<div class="grid-item">...</div>
<div class="grid-item">...</div>
<div class="grid-item">...</div>
</div>
我的CSS:
.grid-item {width: 33%}
和js:
$('.grid').isotope({
itemSelector: '.grid-item',
columnWidth: '.grid-item',
percentPosition: true,
});
在网格项内我有 img,它们的高度可以不同,那么我该怎么办?
提前致谢!
同位素非常适合创建这些布局,但它有一些怪癖。在您的情况下,您正在使用图像,这些图像可能决定布局的计算方式。我建议您使用同一作者的 imagesLoaded 库,首先检查图像是否已加载,然后渲染布局。否则,在加载图像之前,砌体布局中的项目将没有任何高度。
如果您想要顶部和底部平坦的布局,那么您将需要一些固定的高度值。如果图像的完整比例比高度更重要,那么这是不可能的。
您可以使用 CSS 中的
object-fit
属性为图像提供 background-size: cover
类型的效果。它将确保任何给定的图像将覆盖砌体网格中项目的整个空间。
在这些示例中,我使用了多个不同大小的图像,尽管存在差异,但它们都可以正常工作。
查看下面带有同位素和图像的片段。
var $grid = $('.grid').imagesLoaded( function() {
$grid.isotope({
itemSelector: '.grid-item',
percentPosition: true,
masonry: {
columnWidth: '.grid-item',
}
});
});
*, *::before, *::after {
box-sizing: border-box;
}
.grid-item {
position: relative;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
width: 33.3333333%;
height: auto;
}
.grid-item.is-wide {
width: 66.6666666%;
}
.grid-item::before {
content: "";
grid-area: 1 / 1 / 2 / 2;
display: block;
}
.grid-item::before,
.grid-item.is-wide.is-high::before {
padding-top: 100%;
}
.grid-item.is-wide::before {
padding-top: 50%;
}
.grid-item.is-high::before {
padding-top: 200%;
}
.grid-item img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
padding: 5px;
-o-object-fit: cover;
object-fit: cover;
z-index: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://unpkg.com/imagesloaded@4/imagesloaded.pkgd.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.isotope/3.0.6/isotope.pkgd.min.js"></script>
<div class="grid">
<div class="grid-item">
<img src="https://www.fillmurray.com/640/360" alt="640x360"/>
</div>
<div class="grid-item is-wide">
<img src="https://www.fillmurray.com/360/640" alt="360x640"/>
</div>
<div class="grid-item is-high">
<img src="https://www.fillmurray.com/420/420" alt="420x420"/>
</div>
<div class="grid-item">
<img src="https://www.fillmurray.com/640/360" alt="640x360"/>
</div>
<div class="grid-item ">
<img src="https://www.fillmurray.com/640/800" alt="640x800"/>
</div>
<div class="grid-item is-wide">
<img src="https://www.fillmurray.com/480/320" alt="640x360"/>
</div>
<div class="grid-item">
<img src="https://www.fillmurray.com/640/360" alt="640x360"/>
</div>
<div class="grid-item">
<img src="https://www.fillmurray.com/360/640" alt="360x640"/>
</div>
<div class="grid-item is-wide">
<img src="https://www.fillmurray.com/420/420" alt="420x420"/>
</div>
<div class="grid-item is-high">
<img src="https://www.fillmurray.com/640/360" alt="640x360"/>
</div>
<div class="grid-item">
<img src="https://www.fillmurray.com/640/800" alt="640x800"/>
</div>
<div class="grid-item is-wide">
<img src="https://www.fillmurray.com/480/320" alt="640x360"/>
</div>
</div>
您需要重写布局计算才能实现这一点。
现在,如果项目跨越多列,这可能会很复杂。但是,如果每个项目仅跨越一列,则相当容易做到。
逻辑:
_getTopColPosition
,它的作用与以前相同,但我们为每个元素分配一个 col
属性,这样我们稍后就会知道它位于哪一列。 这是示例代码:
var elem = document.querySelector('.grid');
var isotope = new Isotope( elem, {
// options
itemSelector: '.grid-item',
layoutMode: 'masonry' // Note: this solution only works with 'masonry' layout!
});
const layoutMode = isotope._mode()
const _getTopColPosition = layoutMode._getTopColPosition
layoutMode._getTopColPosition = function( colSpan, item ) {
const result = _getTopColPosition.apply( layoutMode, arguments );
item.col = result.col;
return result;
};
const _getHorizontalColPosition = layoutMode._getHorizontalColPosition
layoutMode._getHorizontalColPosition = function( colSpan, item ) {
const result = _getHorizontalColPosition.apply( layoutMode, arguments );
item.col = result.col;
return result;
};
const isotypeProto = Object.getPrototypeOf(isotope);
isotypeProto._processLayoutQueue = function( queue ) {
equalizeProcessPositions(queue);
this.updateStagger();
queue.forEach( function( obj, i ) {
isotypeProto._positionItem( obj.item, obj.x, obj.y, obj.isInstant, i );
}, this );
}
function equalizeProcessPositions(queue) {
// Each item has a col attribute. Sort them into an object where the col number is the key and each value is an array of items
const entriesByCol = queue.reduce((acc, entry) => {
if (!acc[entry.item.col]) {
acc[entry.item.col] = [];
}
acc[entry.item.col].push(entry);
return acc;
}, {});
const colYs = {};
// Get maxY for each col, i.e. the y position and the height of the last item
for (const [col, entry] of Object.entries(entriesByCol)) {
const lastEntry = entriesByCol[col][entriesByCol[col].length - 1];
colYs[col] = lastEntry.y + lastEntry.item.size.outerHeight;
}
const maxY = Math.max(...layoutMode.colYs);
// Now adjust the items in each col
for (const [col, colY] of Object.entries(colYs)) {
if (colY !== maxY) {
const diff = maxY - colY;
const items = entriesByCol[col].length;
const adjustment = diff / (items);
// Loop each item in itemsByCol[i] and adjust the height and position
for (const [i, entry] of Object.entries(entriesByCol[col])) {
entry.item.size.innerHeight += adjustment;
entry.item.size.outerHeight += adjustment;
entry.item.size.height += adjustment;
entry.item.element.style.height = entry.item.size.outerHeight + 'px';
entry.y += i * adjustment;
}
}
}
}
const _resetLayout = layoutMode._resetLayout
layoutMode._resetLayout = function() {
this.items.forEach(item => {
item.element.style.height = '';
})
return _resetLayout.apply( layoutMode, arguments );
};