我有动态内容和响应式布局,因此项目数和可用宽度会有所不同。有时div中的元素需要包含在第二行中。
使用flexbox(或任何其他CSS方法),您可以使每行上的项目数相等吗?
<div class="cont">
<div class="elem"></div>
<div class="elem"></div>
<div class="elem"></div>
<div class="elem"></div>
<div class="elem"></div>
<div class="elem"></div>
<div class="elem"></div>
</div>
.cont {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
border: 1px solid grey;
margin: auto;
width: 60%;
padding: 10px;
}
.elem {
height: 100px;
width: 100px;
border: 1px solid blue;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
margin-right: 10px;
margin-bottom: 10px;
}
http://codepen.io/anon/pen/qEQzqY
答案 0 :(得分:2)
如果元素的数量在合理范围内,则使用quantity queries技术为每个案例编写css可能是可行的。
答案 1 :(得分:1)
正如dalgard所说,如果你想要一个CSS解决方案,数量查询是一个解决方案。
但是,您需要编写几个案例
让我们看看它适用于七元素案例
.cont {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-flex-wrap: wrap;
-ms-flex-wrap: wrap;
flex-wrap: wrap;
border: 1px solid grey;
margin: auto;
width: 500px;
padding: 10px;
}
.elem {
height: 100px;
width: 100px;
border: 1px solid blue;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
margin-right: 10px;
margin-bottom: 10px;
}
.elem:nth-last-child(7):first-child {
border-color: red;
}
.elem:nth-last-child(7):first-child ~ .elem:nth-child(3) {
border-color: green;
margin-right: 100px;
}
<div class="cont">
<div class="elem"></div>
<div class="elem"></div>
<div class="elem"></div>
<div class="elem"></div>
<div class="elem"></div>
<div class="elem"></div>
<div class="elem"></div>
</div>
<div class="cont">
<div class="elem"></div>
<div class="elem"></div>
<div class="elem"></div>
<div class="elem"></div>
<div class="elem"></div>
<div class="elem"></div>
<div class="elem"></div>
<div class="elem"></div>
</div>
我设置了红色边框规则只是为了表明它适用于七个元素的情况,但不适用于其他情况。然后,第三个元素的目标是使行完成(并使用不同的边框颜色显示以使其可见
答案 2 :(得分:1)
我迟到了2年多,我很喜欢Maksym Stepanenko的想法。 我最初尝试使用flexbox的纯css解决方案:
flex-direction: column;
align-content: flex-start;
但这需要您指定高度,并根据需要调整高度。
因此,使用Maksym Stepanenko根据需要调整margin-right的想法的备份方法,无论哪种方式都适用于浮动元素或flexbox包装元素。 我最后纠正了一些Maksym Stepanenko对这个例子的计算:
JS BIN Link或下面的代码段(使用库“检测元素调整大小”,以便容器侦听器工作)。
/**
* Detect Element Resize
*
* https://github.com/sdecima/javascript-detect-element-resize
* Sebastian Decima
*
* version: 0.5.3
**/
(function () {
var attachEvent = document.attachEvent,
stylesCreated = false;
if (!attachEvent) {
var requestFrame = (function(){
var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
function(fn){ return window.setTimeout(fn, 20); };
return function(fn){ return raf(fn); };
})();
var cancelFrame = (function(){
var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame ||
window.clearTimeout;
return function(id){ return cancel(id); };
})();
function resetTriggers(element){
var triggers = element.__resizeTriggers__,
expand = triggers.firstElementChild,
contract = triggers.lastElementChild,
expandChild = expand.firstElementChild;
contract.scrollLeft = contract.scrollWidth;
contract.scrollTop = contract.scrollHeight;
expandChild.style.width = expand.offsetWidth + 1 + 'px';
expandChild.style.height = expand.offsetHeight + 1 + 'px';
expand.scrollLeft = expand.scrollWidth;
expand.scrollTop = expand.scrollHeight;
};
function checkTriggers(element){
return element.offsetWidth != element.__resizeLast__.width ||
element.offsetHeight != element.__resizeLast__.height;
}
function scrollListener(e){
var element = this;
resetTriggers(this);
if (this.__resizeRAF__) cancelFrame(this.__resizeRAF__);
this.__resizeRAF__ = requestFrame(function(){
if (checkTriggers(element)) {
element.__resizeLast__.width = element.offsetWidth;
element.__resizeLast__.height = element.offsetHeight;
element.__resizeListeners__.forEach(function(fn){
fn.call(element, e);
});
}
});
};
/* Detect CSS Animations support to detect element display/re-attach */
var animation = false,
animationstring = 'animation',
keyframeprefix = '',
animationstartevent = 'animationstart',
domPrefixes = 'Webkit Moz O ms'.split(' '),
startEvents = 'webkitAnimationStart animationstart oAnimationStart MSAnimationStart'.split(' '),
pfx = '';
{
var elm = document.createElement('fakeelement');
if( elm.style.animationName !== undefined ) { animation = true; }
if( animation === false ) {
for( var i = 0; i < domPrefixes.length; i++ ) {
if( elm.style[ domPrefixes[i] + 'AnimationName' ] !== undefined ) {
pfx = domPrefixes[ i ];
animationstring = pfx + 'Animation';
keyframeprefix = '-' + pfx.toLowerCase() + '-';
animationstartevent = startEvents[ i ];
animation = true;
break;
}
}
}
}
var animationName = 'resizeanim';
var animationKeyframes = '@' + keyframeprefix + 'keyframes ' + animationName + ' { from { opacity: 0; } to { opacity: 0; } } ';
var animationStyle = keyframeprefix + 'animation: 1ms ' + animationName + '; ';
}
function createStyles() {
if (!stylesCreated) {
//opacity:0 works around a chrome bug https://code.google.com/p/chromium/issues/detail?id=286360
var css = (animationKeyframes ? animationKeyframes : '') +
'.resize-triggers { ' + (animationStyle ? animationStyle : '') + 'visibility: hidden; opacity: 0; } ' +
'.resize-triggers, .resize-triggers > div, .contract-trigger:before { content: \" \"; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; } .resize-triggers > div { background: #eee; overflow: auto; } .contract-trigger:before { width: 200%; height: 200%; }',
head = document.head || document.getElementsByTagName('head')[0],
style = document.createElement('style');
style.type = 'text/css';
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
head.appendChild(style);
stylesCreated = true;
}
}
window.addResizeListener = function(element, fn){
if (attachEvent) element.attachEvent('onresize', fn);
else {
if (!element.__resizeTriggers__) {
if (getComputedStyle(element).position == 'static') element.style.position = 'relative';
createStyles();
element.__resizeLast__ = {};
element.__resizeListeners__ = [];
(element.__resizeTriggers__ = document.createElement('div')).className = 'resize-triggers';
element.__resizeTriggers__.innerHTML = '<div class="expand-trigger"><div></div></div>' +
'<div class="contract-trigger"></div>';
element.appendChild(element.__resizeTriggers__);
resetTriggers(element);
element.addEventListener('scroll', scrollListener, true);
/* Listen for a css animation to detect element display/re-attach */
animationstartevent && element.__resizeTriggers__.addEventListener(animationstartevent, function(e) {
if(e.animationName == animationName)
resetTriggers(element);
});
}
element.__resizeListeners__.push(fn);
}
};
window.removeResizeListener = function(element, fn){
if (attachEvent) element.detachEvent('onresize', fn);
else {
element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
if (!element.__resizeListeners__.length) {
element.removeEventListener('scroll', scrollListener);
element.__resizeTriggers__ = !element.removeChild(element.__resizeTriggers__);
}
}
}
})();
<!doctype html>
<head>
<meta charset="UTF-8">
<style>
.flex{ display: -webkit-flex; display: -ms-flexbox; display: flex; }
.wrap{ -webkit-flex-wrap: wrap; -ms-flex-wrap: wrap; flex-wrap: wrap;}
.cont {
border: 1px solid grey;
margin: auto;
width: 448px;
padding-right: 0;
padding-bottom: 0;
/*flex-direction: column;height: 225px;align-content: flex-start;*/
}
.controls{
width: 500px;
margin: auto;
justify-content: space-around;
text-align: center;
}
.elem {
border: 1px solid blue;
text-align:center;
}
input{
width: 25px; color: blue;
}
#resizableBorder{
resize: horizontal;
overflow: auto;
}
</style>
<style id="jsManipulated">
.elem {
height: 100px;
width: 100px;
line-height: 100px;
margin-right: 10px;
margin-bottom: 10px;
}
.cont {
padding-top: 10px;
padding-left: 10px;
}
</style>
</head>
<body>
<br>
<div class="flex controls">
<button id="adder">(+) add item</button>
<button id="remover">(-) remove item</button>
<span> Box Size:
<input id="sizer" type="text" value="100" boxCountlength="3" onkeypress='return event.charCode > 47 && event.charCode < 58'>
</span>
<span> Padding:
<input id="padder" type="text" value="10" boxCountlength="3" >
</div>
<br><hr><br>
<div id="resizableBorder" class="cont flex wrap">
<div class="elem"> 1</div><div class="elem"> 2</div><div class="elem"> 3</div>
<div class="elem"> 4</div><div class="elem"> 5</div><div class="elem"> 6</div>
<div class="elem"> 7</div><div class="elem"> 8</div><div class="elem"> 9</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function(){
var boxCount = 9;
var boxWidth = 100;
var boxBorderWidth = 10;
var adder = document.getElementById('adder');
var remover = document.getElementById('remover');
var sizer = document.getElementById('sizer');
var padder = document.getElementById('padder');
var flexParent = document.getElementsByClassName('cont')[0];
var styleEle = document.getElementById('jsManipulated');
var resizableBorder = document.getElementById('resizableBorder');
function addItem(){
console.log("add");
var newItem = document.createElement('div');
newItem.className += 'elem';
newItem.innerHTML = ++boxCount;
flexParent.appendChild( newItem );
repaint();
}
function removeItem(){
console.log("remove");
if(boxCount != 0){
--boxCount;
//flexParent.removeChild(flexParent.lastChild);
var position = flexParent.children.length -1;
if( flexParent.children[position].className == "resize-triggers"){ --position; } //ignore resize-triggers div.
flexParent.removeChild( flexParent.children[ position ] );
repaint();
}
}
function resizeBoxes(event) {
if( event.keyCode > 47 && event.keyCode < 58){ boxWidth = this.value; }
else if( event.keyCode == 40 ){ boxWidth = --this.value; }
else if( event.keyCode == 38 ){ boxWidth = ++this.value; }
else {
console.log('non-numeric keypress ignored: '+event.keyCode);
return;
}
updateBoxStyles( boxWidth, boxBorderWidth);
}
function repadBoxes(event) {
if( event.keyCode > 47 && event.keyCode < 58){ boxBorderWidth= this.value; }
else if( event.keyCode == 40 ){ boxBorderWidth = --this.value; }
else if( event.keyCode == 38 ){ boxBorderWidth = ++this.value;}
else {
console.log('non-numeric keypress ignored: '+event.keyCode);
return;
}
updateBoxStyles( boxWidth, boxBorderWidth);
}
function updateBoxStyles( size, edge ){
styleEle.innerHTML =
".elem { height: "
+size+"px; width: "
+size+"px; line-height: "
+size+"px; margin-right: "
+edge+"px; margin-bottom: "
+edge+"px;} .cont { padding-top: "
+edge+"px; padding-left: "
+edge+"px;}"
repaint();
}
/* LISTENERS */
window.onresize = repaint; //Only needed if 'width' of container is a percentage ex: '.cont{width:60%}'
adder.addEventListener('click', addItem );
remover.addEventListener('click', removeItem );
sizer.addEventListener('keyup', resizeBoxes );
padder.addEventListener('keyup', repadBoxes );
addResizeListener( resizableBorder, repaint); //using the 'detect-element-resize.js library'
/** Most Important Function Called Everytime Anything Changes, in order to keep elements to the left using 'margin-right' **/
repaint(); //initial resize on pageload;
function repaint() {
console.log('repaint');
var elementWidth = 2- -boxWidth- -boxBorderWidth; // 2 because: border is 1px*2, '- -' because '+' causes string concatination.
var elements = document.getElementsByClassName('elem');
var count = elements.length;
var parentWidth = parseInt( window.getComputedStyle( flexParent).getPropertyValue('width') );
var rowsCount = Math.ceil( count / Math.floor(parentWidth/elementWidth) );
var perRow = Math.floor( count / rowsCount);
var extra = count % rowsCount;
for (var i=0, ele; ele = elements[i]; i++) {
ele.style["margin-right"] = "";
}
if( rowsCount == Infinity || rowsCount == 0){ return; }//when elementWidth < parentWidth or Zero Boxes
var allPrevRowsTotal = 0;
for (var i = 1; i <= rowsCount && rowsCount > 1; i++) {
var perThisRow = perRow;
if( extra != 0){ --extra; perThisRow++; }
elements[ allPrevRowsTotal + perThisRow - 1 ].style["margin-right"] = parentWidth - (perThisRow * elementWidth) +"px";
allPrevRowsTotal += perThisRow;
}
}
});
//https://stackoverflow.com/questions/29125444/equal-number-of-element-per-row-with-flexbox
</script>
</body>
答案 3 :(得分:0)
虽然您要求Css解决方案我找不到,所以我创建了一个基于jquery的解决方案(我假设可以进行优化)。
此解决方案仅在您知道项目宽度时有效,并且在示例中是静态的(目前112px
border
和margin
)。
希望这能满足您的需求。
Css和HTML不变
$(window).resize(function () {
var elementWidth = 112;
var Elements = $(".elem");
var parentWidth = $(".cont").width();
var rowsCount = Math.ceil((Elements.length * elementWidth) / parentWidth);
var perRow = Math.ceil(Elements.length / rowsCount);
perRow = perRow * elementWidth > parentWidth ? perRow - 1 : perRow;
$.each(Elements, function (index, item) {
$(this).css("margin-right", "");
});
for (i = 1; i <= rowsCount && rowsCount > 1; i++) {
if (i * perRow <= Elements.length) Elements.eq((i * perRow) - 1).css("margin-right", parentWidth - (perRow * elementWidth));
}
});
尚未对所有屏幕尺寸和不同数量的元素进行测试, 只是几个案例,所以我可能会在某些时候失败。