我有一个在单元格中绘制正方形的网格。它具有行数和列数,然后绘制网格单元格并检查每个单元格中是否应该有一个正方形(根据数组),并在需要时绘制一个正方形。 HTML 最终结果看起来像这样:(假设我有 1 行和 3 列,只有 2 个单元格应该有正方形)
.row { display: flex; flex-wrap: wrap; flex: 10000 1 0%; } .column { display: flex; flex-wrap: wrap; max-width: 100px; min-width: 10px; padding: 4px; border: 1px solid grey; } .square { background-color: red; width: 100%; aspect-ratio: 1/1; border-radius: 5px; }
<div class="row"> <div class="column"> <div class="square"></div> </div> <div class="column"> <div class="square"></div> </div> <div class="column"></div> </div>
行占据屏幕的整个宽度,所有列之间的列大小应该相同,并根据屏幕上的列数进行更改(例如,如果我有 5 列,它们都应该带有宽度为 100 像素,但如果我有 1000 列,它们的宽度都应该为 10 像素)。
我的问题是,在列大小中的某个断点之后,填充和边框半径看起来很奇怪,我想在遇到该断点时更改它们的值。 我无法使用 @container 查询,因为仍然没有完全支持。
如果它有帮助,我正在使用 vue 2。但我认为在这种情况下 CSS 解决方案会更好。
P粉4278776762024-04-04 14:37:48
尝试解决所描述的问题:
我制作了一个小演示,帮助我更好地探索实现这种场景的条件。
.row
元素仍然是一个 Flexbox 容器,但它的 Flex 项目没有设置 border
,而是使用 outline
设置进行样式设置.
轮廓不占用空间,当与另一个元素生成的轮廓碰撞时,它会“崩溃”。
因此,为了确保布局不受样式奇怪的影响,在尝试展示 Flex 项目的边框时,此演示仅依赖于 2 个关键方面来渲染这些边框:
间隙
轮廓
大小,以覆盖之间留下的间隙
元素.row { gap: var(--col-gap); } .column { outline: var(--col-gap) solid gray; }
另外,红点被应用为具有 position:absolute
的 ::after
伪元素,再次确保没有任何内容影响网格布局:
.column.square::after { position: absolute; content: ''; background-color: red; width: 50%; aspect-ratio: 1/1; border-radius: 100%; top: 50%; left: 50%; transform: translate(-50%, -50%); }
从那里开始,我添加了一个带有 position:fixed
的“仪表板”,它保留在页面顶部并允许您控制:
display: none;
不会更改网格布局它完全取决于通过自定义变量 --col-width
设置的 .column
元素大小尽管我们努力最大限度地减少干扰,并采取了仅根据单元格的固定大小正确设置网格布局所需的所有步骤,但仍然存在一些问题渲染问题,有时某些线条的边框尺寸会出现常规的不匹配图案。 我应该说,我只在笔记本电脑显示屏上遇到问题,而不是在台式机显示器上,所以这是另一个因素。
我在演示中尝试了不同的参数并处理数字,同时也考虑到了差距。良好且安全的布局可以最大限度地减少潜在问题(例如,还可以提高边框尺寸)。
使用 Flex 布局我无法得到比这更进一步的结果。
const container = document.getElementById('container');
//draws the board
emptyElementAndFillWithColumns(container, 100);
//sets some columns randomly as .square
addRandomSquares(container);
//initializes the dashboard with the value coming from the css custom props
let columnsGap = parseInt(getCssCustomProp('col-gap'));
let columnsWidth = parseInt(getCssCustomProp('col-width'));
document.getElementById('gap').value = columnsGap;
document.getElementById('width').value = columnsWidth;
document.getElementById('width').dispatchEvent(new Event('change'));
document.getElementById('cols').value = Math.trunc(container.offsetWidth / (columnsWidth+columnsGap));
//input#width change event handler
document.getElementById('width')
.addEventListener('change', event => {
const width = parseInt(event.target.value);
const newCols = Math.trunc(container.offsetWidth / (width+columnsGap));
setCssCustomProp(container, 'col-width', `${width}px`);
document.getElementById('cols').value = newCols;
});
//input#cols change event handler
document.getElementById('cols')
.addEventListener('change', event => {
const cols = parseInt(event.target.value);
const newWidth = Math.trunc(container.offsetWidth / cols) - columnsGap;
setCssCustomProp(container, 'col-width', `${newWidth}px`);
document.getElementById('width').value = newWidth;
});
//input#gap change event handler
document.getElementById('gap')
.addEventListener('change', event => {
const gap = parseInt(event.target.value);
setCssCustomProp(container, 'col-gap', `${gap}px`);
columnsGap = gap;
});
//input#toggle-dots change event handler
document.getElementById('toggle-dots')
.addEventListener('change', event => {
container.classList.toggle('hide-dots');
});
//input#toggle-counters change event handler
document.getElementById('toggle-counters')
.addEventListener('change', event => {
container.classList.toggle('hide-counters');
});
//sets the --propName custom property at the style of target
function setCssCustomProp(target, propName, value){
target.style.setProperty(`--${propName}`, `${value}`);
}
//gets the --propName custom property value from the rule set on :root
function getCssCustomProp(propName){
const propValue =
getComputedStyle(document.documentElement).getPropertyValue(`--${propName}`);
return propValue;
}
//resets the container and appends a count number of columns
function emptyElementAndFillWithColumns(target, count){
for (i = 0; i <= count; i++) {
const column = document.createElement('div');
column.classList.add('column');
target.append(column);
}
}
//adds the square class to random .column elements in target
function addRandomSquares(target){
target.querySelectorAll('.column').forEach(column => {
if (Math.random() >= 0.5)
column.classList.add('square');
})
}
:root {
--col-width: 100px;
--col-gap: 1px;
}
*,
*::after,
*::before {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: sans-serif;
}
.row {
display: flex;
flex-wrap: wrap;
gap: var(--col-gap);
counter-reset: itemnr;
}
.column {
position: relative;
display: flex;
flex-wrap: wrap;
width: var(--col-width);
height: var(--col-width);
padding: 4px;
outline: var(--col-gap) solid gray;
}
.column.square::after {
position: absolute;
content: '';
background-color: red;
width: 50%;
aspect-ratio: 1/1;
border-radius: 100%;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.dashboard {
position: fixed;
right: 1rem;
top: 2rem;
border: solid darkgray;
padding: 1em;
z-index: 100;
background: gray;
color: white;
font-weight: 600;
font-size: 1.2rem;
opacity: .9;
}
.dashboard > *{
display: grid;
grid-template-columns: 1fr auto;
width: 100%;
gap: 1em;
}
.dashboard label{
}
.dashboard input[type="number"] {
width: 5em;
cursor: pointer;
}
.dashboard input[type="checkbox"] {
width: 1rem;
line-height: 1rem;
cursor: pointer;
}
#container.hide-dots .square::after{
display: none;
}
#container.hide-counters .column::before{
display: none;
}
small{
grid-column: 1 / -1;
font-size:.8rem;
text-align: center;
width: 100%;
margin-bottom: 1rem;
}
.column::before{
position: absolute;
counter-increment: itemnr;
content: counter(itemnr);
font-size: .8rem;
z-index: 10;
font-weight: 600;
}