and*_*tor 7 css css3 css-multicolumn-layout
我正在尝试实施一个超级菜单.
菜单项的数量是可变的.默认情况下,它们必须以4列呈现,平衡(每列上的项目数应与其他列几乎相同).根据其内容,巨型菜单的高度也是可变的.
我用CSS多列布局实现了它.
这个代码是:
.menu {
-webkit-column-count: 4;
-moz-column-count: 4;
column-count: 4;
-webkit-column-gap: 32px;
-moz-column-gap: 32px;
column-gap: 32px;
}
Run Code Online (Sandbox Code Playgroud)
我的问题是有一个特殊的菜单项类型,它应该作为一个列中断.此菜单项类型是可选的,但如果存在,则应强制浏览器启动新列以显示内容(最多可以有3个列中断).
我添加了以下css代码:
.menu-item--column-break {
display: block;
-webkit-column-break-before: column;
-moz-break-before: column;
break-before: column;
}
Run Code Online (Sandbox Code Playgroud)
但是这个CSS仅适用于Chrome:
Firefox和Safari不支持"column-break"元素的CSS规则,并将其显示为普通菜单项:
该菜单是在JavaScript中从JSON对象生成的,HTML可以更改,但我更喜欢CSS/JS-only解决方案.
您是否知道如何在所有浏览器中实现此功能?
这是完整的代码:
https://codepen.io/andreivictor/pen/ywLJKx
要么
let items = [
{title: 'Category 1', type: 'menu-item'},
{title: 'Category 2', type: 'menu-item'},
{title: '---cb---', type: 'column-break'},
{title: 'Category 3', type: 'menu-item'},
{title: 'Category 4', type: 'menu-item'},
{title: 'Category 5', type: 'menu-item'},
{title: 'Category 6', type: 'menu-item'},
{title: 'Category 7', type: 'menu-item'},
{title: 'Category 8', type: 'menu-item'},
{title: 'Category 9', type: 'menu-item'},
{title: '---cb---', type: 'column-break'},
{title: 'Category 10', type: 'menu-item'},
{title: 'Category 11', type: 'menu-item'},
{title: 'Category 12', type: 'menu-item'},
{title: 'Category 13', type: 'menu-item'},
{title: 'Category 14', type: 'menu-item'},
{title: 'Category 15', type: 'menu-item'},
{title: 'Category 16', type: 'menu-item'},
{title: 'Category 17', type: 'menu-item'},
{title: 'Category 18', type: 'menu-item'},
{title: 'Category 19', type: 'menu-item'},
{title: 'Category 20', type: 'menu-item'},
{title: 'Category 21', type: 'menu-item'},
];
const $menu = document.querySelector('.menu');
console.log( $menu );
items.forEach((item) => {
let nodeItem = document.createElement("div");
nodeItem.classList.add('menu-item');
let nodeItemText = document.createTextNode(item.title);
nodeItem.appendChild(nodeItemText);
if (item.type === 'column-break') {
nodeItem.classList.add('menu-item--column-break');
}
$menu.appendChild(nodeItem);
});
Run Code Online (Sandbox Code Playgroud)
.menu {
position: relative;
padding: 0 16px;
-webkit-column-count: 4;
-moz-column-count: 4;
column-count: 4;
-moz-column-rule: 1px solid #e2e1e1;
column-rule: 1px solid #e2e1e1;
-webkit-column-gap: 32px;
-moz-column-gap: 32px;
column-gap: 32px;
}
.menu-item--column-break {
display: block;
-webkit-column-break-after: column;
-moz-break-after: column;
break-after: column;
color: red;
}
Run Code Online (Sandbox Code Playgroud)
<div class="container">
<div class="menu">
</div>
</div>
Run Code Online (Sandbox Code Playgroud)
我正在思考这个问题并提出了另一个解决方案。基本上问题是不支持多列拆分,因此目前无法仅使用 css 为所有浏览器创建这些固定列和动态列。因此我决定将问题一分为二。我根据固定休息时间将项目分成几组。我假设每个组都会成为一栏,供初学者使用。然后我会看到我有多少列。如果它小于 4(您想要的列数),那么我允许最大的组动态地再分成一列。我继续此操作,直到达到 4 列的总数 - 无论是固定的、动态的,还是两者兼而有之。
请参阅下面的片段。
此外,还可以通过添加、删除或移动断点来调整剪裁。它应该适用于许多不同的场景。
let items = [
{title: 'Category 1', type: 'menu-item'},
{title: 'Category 2', type: 'menu-item'},
{title: '---cb---', type: 'column-break'},
{title: 'Category 3', type: 'menu-item'},
{title: 'Category 4', type: 'menu-item'},
{title: 'Category 5', type: 'menu-item'},
{title: 'Category 6', type: 'menu-item'},
{title: 'Category 7', type: 'menu-item'},
{title: 'Category 8', type: 'menu-item'},
{title: 'Category 9', type: 'menu-item'},
{title: '---cb---', type: 'column-break'},
{title: 'Category 10', type: 'menu-item'},
{title: 'Category 11', type: 'menu-item'},
{title: 'Category 12', type: 'menu-item'},
{title: 'Category 13', type: 'menu-item'},
{title: 'Category 14', type: 'menu-item'},
{title: 'Category 15', type: 'menu-item'},
//{title: '---cb---', type: 'column-break'},
{title: 'Category 16', type: 'menu-item'},
{title: 'Category 17', type: 'menu-item'},
{title: 'Category 18', type: 'menu-item'},
{title: 'Category 19', type: 'menu-item'},
{title: 'Category 20', type: 'menu-item'},
{title: 'Category 21', type: 'menu-item'}
];
const $menu = document.querySelector('.menu');
var allGroups = [];
var currentGroup = 0;
allGroups.push({ items: [], columns: 1});
function addGroup($menu, group, numberOfColumns){
let columnItem = document.createElement("div");
columnItem.classList.add('menu-group');
if(numberOfColumns === 1){
columnItem.classList.add('fixed');
} else {
columnItem.classList.add('dynamic-columns');
var style = '-webkit-column-count: ' + numberOfColumns + ';';
style += '-moz-column-count: ' + numberOfColumns + ';';
style += 'column-count: ' + numberOfColumns + ';';
columnItem.setAttribute('style', style);
}
group.forEach((groupItem) => {
columnItem.appendChild(groupItem);
});
$menu.appendChild(columnItem);
};
var columnsCount = 1;
items.forEach((item) => {
let nodeItem = document.createElement("div");
allGroups[currentGroup].items.push(nodeItem);
nodeItem.classList.add('menu-item');
let nodeItemText = document.createTextNode(item.title);
nodeItem.appendChild(nodeItemText);
if (item.type === 'column-break') {
nodeItem.classList.add('menu-item--column-break');
//addGroup($menu, currentGroup, 1);
currentGroup++;
allGroups.push({ items: [], columns: 1});
columnsCount++;
}
});
var forSorting = [];
allGroups.forEach((item) => { forSorting.push(item); });
while(columnsCount < 4){
forSorting.sort(function(a, b){
return (b.items.length/b.columns) - (a.items.length/a.columns);
});
forSorting[0].columns++;
columnsCount++;
}
allGroups.forEach((item) => {
addGroup($menu, item.items, item.columns);
});
Run Code Online (Sandbox Code Playgroud)
.menu {
position: relative;
padding: 0 16px;
display: flex;
flex-direction: row;
}
.menu-group:not(:last-child){
border-right: 1px solid #e2e1e1;
margin-right: 8px;
}
.menu-group.fixed {
flex-basis: calc(25% - 8px);
flex-grow: 0;
flex-shrink: 0;
}
.menu-group.dynamic-columns {
flex-grow: 1;
-moz-column-rule: 1px solid #e2e1e1;
column-rule: 1px solid #e2e1e1;
}
.menu-item--column-break {
display: block;
color: red;
}
Run Code Online (Sandbox Code Playgroud)
<div class="container">
<div class="menu">
</div>
</div>
Run Code Online (Sandbox Code Playgroud)