搜索

首页  >  问答  >  正文

随着父元素变小,减少填充大小

我有一个在单元格中绘制正方形的网格。它具有行数和列数,然后绘制网格单元格并检查每个单元格中是否应该有一个正方形(根据数组),并在需要时绘制一个正方形。 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粉807397973P粉807397973268 天前391

全部回复(1)我来回复

  • P粉427877676

    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;
    }

    使用 ::after 将内容添加到元素

    另外,红点被应用为具有 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 的“仪表板”,它保留在页面顶部并允许您控制:

    • 列宽(px):您可以在此处设置宽度,根据可用的容器空间更改每行的列数
    • 每行列数:在这里您可以设置每行的列数,根据可用的容器空间更改其宽度 宽度
    • 单元格之间的间隙(px):网格上单元格之间的间隙
    • 切换红点可见性:将显示/隐藏红点,再次证明 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;
    }

    回复
    0
  • 取消回复