【问题标题】:Flexible layout: Is this one possible?灵活的布局:这可能吗?
【发布时间】:2022-01-25 13:19:03
【问题描述】:

编辑 请记住,每个单元格可以有不同的宽度和高度。这和这个帖子不是一回事:CSS-only masonry layout,请看参考图的指引:

大约有 19 列和 17 行由放置在虚拟 5×5 基本网格中的引导线和图块在两个轴上重叠。

我想要介于网格和弹性布局之间的东西。网格受单元格大小的限制,而 flex 更强大,但(据我所知)仅限于方向。我想要不同的单元格大小,每个 5 个单元格的总和为相同的宽度,5 个列的总和为相同的高度。如下图。

有没有办法使用 CSS 实现类似的布局?

这是我到现在为止的全部内容:

HTML:

<div class="calendar">
  <div class="day day1">1</div>
  <div class="day day2">2</div>
  <div class="day day3">3</div>
  <div class="day day4">4</div>
  <div class="day day5">5</div>
  <div class="day day6">6</div>
  <div class="day day7">7</div>
  <div class="day day8">8</div>
  <div class="day day9">9</div>
  <div class="day day10">10</div>
  <div class="day day11">11</div>
  <div class="day day12">12</div>
  <div class="day day13">13</div>
  <div class="day day14">14</div>
  <div class="day day15">15</div>
  <div class="day day16">16</div>
  <div class="day day17">17</div>
  <div class="day day18">18</div>
  <div class="day day19">19</div>
  <div class="day day20">20</div>
  <div class="day day21">21</div>
  <div class="day day22">22</div>
  <div class="day day23">23</div>
  <div class="day day24">24</div>
  <div class="day day25">25</div>
</div>

CSS:

.day {
  margin: 10px;
  color: white;
}

.calendar {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-content: flex-start;
  width: 586px;
  height: 586px;
  border: solid 1px;
}

.day1 {
  width: 87px;
  height: 97px;
  background: lightblue;
}

.day2 {
  width: 151px;
  height: 86px;
  background: orange;
}

.day3 {
  width: 86px;
  height: 86px;
  background: lightcoral;
}

.day4 {
  width: 76px;
  height: 118px;
  background: lightgray;
}

.day5 {
  width: 86px;
  height: 86px;
  background: lightblue;
}

.day6 {
  width: 87px;
  height: 86px;
  background: lightsteelblue;
}

.day7 {
  width: 108px;
  height: 97px;
  background: lightblue;
}

.day8 {
  width: 129px;
  height: 97px;
  background: lightsteelblue;
}

.day9 {
  width: 76px;
  height: 65px;
  background: orange;
}

.day10 {
  width: 86px;
  height: 128px;
  background: cyan;
}

.day11 {
  width: 75px;
  height: 75px;
  background: lightcoral;
}

.day12 {
  width: 99px;
  height: 96px;
  background: lightgray;
}

.day13 {
  width: 87px;
  height: 96px;
  background: lightcyan;
}

.day14 {
  width: 139px;
  height: 96px;
  background: orange;
}

.day15 {
  width: 86px;
  height: 65px;
  background: lightcoral;
}

.day16 {
  width: 75px;
  height: 118px;
  background: orange;
}

.day17 {
  width: 88px;
  height: 97px;
  background: lightcoral;
}

.day18 {
  width: 161px;
  height: 97px;
  background: cyan;
}

.day19 {
  width: 98px;
  height: 118px;
  background: lightgreen;
}

.day20 {
  width: 64px;
  height: 97px;
  background: lightgray;
}

.day21 {
  width: 108px;
  height: 97px;
  background: lightsteelblue;
}

.day22 {
  width: 150px;
  height: 97px;
  background: lightblue;
}

.day23 {
  width: 65px;
  height: 97px;
  background: lightgray;
}

.day24 {
  width: 98px;
  height: 75px;
  background: orange;
}

.day25 {
  width: 65px;
  height: 97px;
  background: lightblue;
}

https://codepen.io/jonathascosta/pen/yLzPPxz

【问题讨论】:

  • 任何你可以用 flex 做的事情,你都可以用 grid 做。事实上,他们一起工作得最好。使用网格进行整体布局,并在网格单元格或区域内弯曲。
  • 您可以手动设置每个图像的绝对定位,同时保持 % 值响应。这听起来像是一个解决方案吗?
  • 使用网格是最好的解决方案
  • @LaaouatniAnas 列和行有不同的大小,是否可以使用网格实现这种布局?怎么样?
  • 我认为CSS不可能完成。例如,如果您尝试查看带有图像的 Google 搜索结果,您会发现它们具有相同的高度。用 Photoshop 画出你展示的图像很容易,但是 HTML 和 CSS 使用盒子模型。我看到的唯一解决方案是手动对齐每个框以获得此结果。但是我怀疑这是你问的。

标签: css flexbox


【解决方案1】:

基本使用CSS GRID

新答案

完整的解释在下面的上一个答案中......

对顶部的边距也使用负边距,例如 (1,4,19) 和底部的正边距

... 

/* here one example */
.day1 {
  grid-column: 1/2;
  margin: 0 0 -2vh 0;
}

.day6 {
  grid-column: 1/2;
  margin: 2vh 0 0 0;
}

...

新代码

body {
  display: grid;
  align-content: center;
  justify-content: center;
  height: 100vh;
}

.calendar {
  display: grid;
  gap: 0.5em;
  height: 80vh;
  width: 80vh;
}

.day {
  border: 3px solid goldenrod;
  padding: 0.1em;
  display: grid;
  place-items: center;
  border-radius: 0.3em;
  transition-duration: 1s;
}

.day:hover {
  background-color: goldenrod;
  color: white;
  transition-duration: 0.5s;
}

.day1 {
  grid-column: 1/2;
  margin: 0 0 -2vh 0;
}

.day2 {
  grid-column: 2/4;
}

.day3 {
  grid-column: 4/5;
}

.day4 {
  grid-column: 5/6;
  margin: 0 0 -6vh 0;
}

.day5 {
  grid-column: 6/7;
}

.day6 {
  grid-column: 1/2;
  margin: 2vh 0 0 0;
}

.day7 {
  grid-column: 2/3;
}

.day8 {
  grid-column: 3/5;
}

.day9 {
  grid-column: 5/6;
  margin: 6vh 0 0 0;
}

.day10 {
  grid-column: 6/7;
}

.day11 {
  grid-column: 1/2;
}

.day12 {
  grid-column: 2/3;
}

.day13 {
  grid-column: 3/4;
}

.day14 {
  grid-column: 4/6;
}

.day15 {
  grid-column: 6/7;
}

.day16 {
  grid-column: 1/2;
}

.day17 {
  grid-column: 2/3;
}

.day18 {
  grid-column: 3/5;
}

.day19 {
  grid-column: 5/6;
  margin: 0 0 -3vh 0;
}

.day20 {
  grid-column: 6/7;
}

.day21 {
  grid-column: 1/2;
}

.day22 {
  grid-column: 2/4;
}

.day23 {
  grid-column: 4/5;
}

.day24 {
  grid-column: 5/6;
  margin: 3vh 0 0 0;
}

.day25 {
  grid-column: 6/7;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="style.css">
</head>

<body>
  <div class="calendar">
    <div class="day day1">1</div>
    <div class="day day2">2</div>
    <div class="day day3">3</div>
    <div class="day day4">4</div>
    <div class="day day5">5</div>
    <div class="day day6">6</div>
    <div class="day day7">7</div>
    <div class="day day8">8</div>
    <div class="day day9">9</div>
    <div class="day day10">10</div>
    <div class="day day11">11</div>
    <div class="day day12">12</div>
    <div class="day day13">13</div>
    <div class="day day14">14</div>
    <div class="day day15">15</div>
    <div class="day day16">16</div>
    <div class="day day17">17</div>
    <div class="day day18">18</div>
    <div class="day day19">19</div>
    <div class="day day20">20</div>
    <div class="day day21">21</div>
    <div class="day day22">22</div>
    <div class="day day23">23</div>
    <div class="day day24">24</div>
    <div class="day day25">25</div>
  </div>
</body>

</html>

上一个答案

有一次我将display: grid 放到父元素(在本例中为.calendar

现在我可以在第 1 天、第 2 天、第 3 天使用...

...这个css属性grid-column

这是grid-column-startgrid-column-end 的简写

使用 FireFox DevTools 我单击代码中的网格按钮,这使我看起来像一个网格可视化工具...

在论文中,我开始思考……我发现最好的方法是创建一个基于网格的 7 列。

这里是以前的代码

body {
  display: grid;
  align-content: center;
  justify-content: center;
  height: 100vh;
}

.calendar {
  display: grid;
  gap: 0.5em;
  height: 80vh;
  width: 80vh;
}

.day {
  border: 2px solid goldenrod;
  padding: 0.1em;
  display: grid;
  place-items: center;
  border-radius: 0.3em;
  transition-duration: 1s;
}

.day:hover {
  background-color: goldenrod;
  color: white;
  transition-duration: 0.5s;
}

.day1 {
  grid-column: 1/2;
}

.day2 {
  grid-column: 2/4;
}

.day3 {
  grid-column: 4/5;
}

.day4 {
  grid-column: 5/6;
}

.day5 {
  grid-column: 6/7;
}

.day6 {
  grid-column: 1/2;
}

.day7 {
  grid-column: 2/3;
}

.day8 {
  grid-column: 3/5;
}

.day9 {
  grid-column: 5/6;
}

.day10 {
  grid-column: 6/7;
}

.day11 {
  grid-column: 1/2;
}

.day12 {
  grid-column: 2/3;
}

.day13 {
  grid-column: 3/4;
}

.day14 {
  grid-column: 4/6;
}

.day15 {
  grid-column: 6/7;
}

.day16 {
  grid-column: 1/2;
}

.day17 {
  grid-column: 2/3;
}

.day18 {
  grid-column: 3/5;
}

.day19 {
  grid-column: 5/6;
}

.day20 {
  grid-column: 6/7;
}

.day21 {
  grid-column: 1/2;
}

.day22 {
  grid-column: 2/4;
}

.day23 {
  grid-column: 4/5;
}

.day24 {
  grid-column: 5/6;
}

.day25 {
  grid-column: 6/7;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="style.css">
</head>

<body>
  <div class="calendar">
    <div class="day day1">1</div>
    <div class="day day2">2</div>
    <div class="day day3">3</div>
    <div class="day day4">4</div>
    <div class="day day5">5</div>
    <div class="day day6">6</div>
    <div class="day day7">7</div>
    <div class="day day8">8</div>
    <div class="day day9">9</div>
    <div class="day day10">10</div>
    <div class="day day11">11</div>
    <div class="day day12">12</div>
    <div class="day day13">13</div>
    <div class="day day14">14</div>
    <div class="day day15">15</div>
    <div class="day day16">16</div>
    <div class="day day17">17</div>
    <div class="day day18">18</div>
    <div class="day day19">19</div>
    <div class="day day20">20</div>
    <div class="day day21">21</div>
    <div class="day day22">22</div>
    <div class="day day23">23</div>
    <div class="day day24">24</div>
    <div class="day day25">25</div>
  </div>
</body>

</html>

【讨论】:

  • 您的物品高度相同。是的,这是可能的,但问题是关于具有不同宽度和高度的项目。
  • 这也需要对grid-row 进行一些更改(我假设我也必须使用它)
  • @Azu 我找到了解决方案!使用边距和负边距(不是最好的解决方案,但效果很好)
  • 是的,如果您手动对齐每个项目,这是可能的。但是,如果您动态加载项目,则此方法不起作用。无论如何,谢谢你的尝试。
  • @JonathasCosta 是的,这是因为被称为复杂网格布局,我尽力帮助你,如果不够好,对不起:(
【解决方案2】:

“正确”答案

没有。包裹的 flex 项目仅分布在单(主轴)轴上。没有自动机制来告诉包装的项目它在之前或之后的运行(上方或下方的行)中的辅助轴上的兄弟姐妹重叠了一些边界,因此应该影响不同行中的项目。由于您的设计涉及两个轴上的重叠,因此无法定义项目的尺寸/变换,并让 flex-box 布局单独进行数学运算以产生所需的平衡分布。

技术上正确的答案

是的。但仅限于精确的“手工”样式。

如上所述,您必须手动为辅助轴上的所有“离网”重叠设置额外的属性。这意味着对于次要,一行中的每个“扩展”项目必须在相邻行中手动“压缩”对应项。当然,这只有在包装完全按照设计发生时才有效。

让我们看一下简化的设计示例:

aaaaaaa..b..cccc
aaaaaaa..b..cccc
aaaaaaa..b..cccc
............cccc
dddd..eeee..cccc
......eeee......
gggg..eeee..ffff
gggg............
gggg..h..iiiiiii
gggg..h..iiiiiii
gggg..h..iiiiiii

ai区域以hb区域为代价横向扩展。同样适用于 c-fd-g 对,只是垂直。正如我们所看到的,重叠发生在两个轴上。假设我们需要四个重叠中的每一个都具有唯一的大小。

使用自定义属性设置宽度/高度“重叠”和相应的辅助轴(垂直)调整的 POC 可以是:

section {
 --base: 9em; /* width & height */
 --add: calc(var(--base) / 8); /* "unit" for overlap adjustments */
 --gap: calc(var(--base) / 20);
 --cols: 3; /* example HTML works with 3 only */
 --dim: calc( ( var(--cols) * var(--base) ) + ( ( var(--cols) - 1 ) * var(--gap) ) );
 width: var(--dim);
 height: var(--dim);
 gap: var(--gap);

 display: flex;
 flex-direction: row;
 flex-wrap: wrap;
}
article {
 width: calc( var(--base) + ( var(--add) * var(--wdt, 0) ) );
 margin-bottom: calc( var(--add) * var(--hgh,0) * -1 ); /* expanded items will "pull" next row back */
 position: relative;
 top: calc( var(--add) * var(--top,0) * 1 );
 height: calc( var(--base) + ( var(--add) * var(--hgh,0) ) );
}

/*
Illustrative
*/
section {
 outline: #F0F6 solid; outline-offset: -2px;
}
article {
 outline: #0FF6 solid; outline-offset: -2px;
 background-color: rgba(0,0,0,0.2);
 align-items: center;
 display: flex;
 justify-content: center;
 flex-direction: column;
 counter-increment: a;
 word-break: break-word;
 text-align: center;
}
article::before { content: counter(a, lower-alpha); }
article::after { content: attr(style); }
:root { background: dimgray; color: snow; }
:link { color: aqua; } :visited { color: lime; }
<section>
 <article style="--wdt: +1;"></article>
 <article style="--wdt: -1;"></article>
 <article style="--hgh: +2;"></article>

 <article style="--hgh: -4"></article>
 <article style="/* defaults */"></article>
 <article style="--hgh: -2; --top: +2"></article>

 <article style="--hgh: +4; --top: -4;"></article>
 <article style="--wdt: -3;"></article>
 <article style="--wdt: +3;"></article>
</section>

这具有很好的灵活性,可以将任何值设置为重叠。

他们说“使用网格”

对于我们刚刚相当复杂的示例设计,具有“3 × 3”基础的网格布局将涉及至少 5 × 5 网格定义:

section {
 grid-template: 
"a a b b c" 60fr
"d e e e c" 10fr
"d e e e f" 20fr
"g e e e f" 30fr
"g h h i i" 60fr
/60fr
   05fr
     20fr
       35fr
         60fr;
 --base: 9em; /* item width & height */
 --gap: calc(var(--base) / 20);
 --cols: 3; /* example HTML works with 3 only */
 --dim: calc( ( var(--cols) * var(--base) ) + ( ( var(--cols) - 1 ) * var(--gap) ) );
 width: var(--dim);
 height: var(--dim);
 gap: var(--gap);
 outline: #F0F6 solid; outline-offset: -2px;
 display: grid;
}

/*
Illustrative
*/
article {
 outline: #0FF6 solid;
 outline-offset: -2px;
 background-color: rgba(0,0,0,.3);
 align-items: center;
 display: flex;
 justify-content: center;
 flex-direction: column;
 counter-increment: a;
 word-break: break-word;
 text-align: center;
}
article::before {
 content: counter(a, lower-alpha);
}
article::after {
 content: attr(style);
}
:root { background: dimgray; color: snow; }
:link { color: aqua; } :visited { color: lime; }
<section class="grid">
 <article style="grid-area: a"></article>
 <article style="grid-area: b"></article>
 <article style="grid-area: c;"></article>

 <article style="grid-area: d;"></article>
 <article style="grid-area: e;"></article>
 <article style="grid-area: f;"></article>

 <article style="grid-area: g;"></article>
 <article style="grid-area: h;"></article>
 <article style="grid-area: i;"></article>
</section>

这种方法的缺点是列-行对上的每个重叠实例都需要额外的列-行定义。问题的具体设计 (5 × 5) 至少需要 19 × 17 的网格定义。


请注意,这两个 POC 都是合成的,并且涉及到相当现代的 gap 用于 flex-box。实际使用很可能比这更复杂。


优雅的网格方法

简单的刚性网格和仅使用边距进行的不规则调整。

这种方法取自other answer of this question,所有荣誉都在那里。

我不知道margin 的网格项目可以做到这一点;添加示例只是为了完整性。使用类似于第一个 flex-box 示例的逻辑:

section {
 --base: 9em; /* item width & height */
 --add: calc(var(--base) / 8); /* "unit" for overlap adjustments */
 --gap: calc(var(--base) / 20);
 --cols: 3; /* example HTML works with 3 only */
 --dim: calc( ( var(--cols) * var(--base) ) + ( ( var(--cols) - 1 ) * var(--gap) ) );
 width: var(--dim);
 height: var(--dim);
 gap: var(--gap);
 display: grid;
 grid-auto-rows: 1fr;
 grid-template-columns: repeat(var(--cols), 1fr);
}
article {
 margin-top: calc( var(--top,0) * var(--add) * -1 );
 margin-right: calc( var(--right,0) * var(--add) * -1 );
 margin-bottom: calc( var(--bottom,0) * var(--add) * -1 );
 margin-left: calc( var(--left,0) * var(--add) * -1 );
}
/*
Illustrative
*/
section {
 outline: #F0F6 solid; outline-offset: -2px;
}
article {
 outline: #0FF6 solid;
 outline-offset: -2px;
 background-color: rgba(0,0,0,.3);
 align-items: center;
 display: flex;
 justify-content: center;
 flex-direction: column;
 counter-increment: a;
 word-break: break-word;
 text-align: center;
}
article::before {
 content: counter(a, lower-alpha);
}
article::after {
 content: attr(style);
}
:root { background: dimgray; color: snow; }
:link { color: aqua; } :visited { color: lime; }
<section>
 <article style="--right: +1;"></article>
 <article style="--left: -1;"></article>
 <article style="--bottom: +2;"></article>

 <article style="--bottom: -4"></article>
 <article style="/* default */"></article>
 <article style="--top: -2"></article>

 <article style="--top: +4;"></article>
 <article style="--right: -3;"></article>
 <article style="--left: +3;"></article>
</section>

我认为这是最优雅、最通用的方式,并且很好地利用了刚性网格进行设计。手动“数字提升”仍然令人生畏——尤其是当需要移动“休息”行甚至更糟糕的整个“桌子”时——但即便如此,它似乎也是最直观的。再次感谢 Laaouatni Anas 将它带到这里。


务实的老派方法:“abspos”

对于真正狂野的刚性不规则设计,请考虑绝对定位。当代码模式中可以容纳一些规则时,显示的弹性盒和第一个网格方法可能对使用有意义。否则,对所有内容使用简单的绝对定位和手动尺寸或使用第二个网格的类似方法可能是同样可行的方法。听起来很糟糕 - 将物品重新放置在更下方或更右侧会很痛苦 - 但如果证明是完成这项特定任务的最佳解决方案,我不会感到惊讶。


【讨论】:

  • 非常好的解释,非常感谢。
【解决方案3】:

您仍然可以保留弹性结构,因为您使用的是flex-wrap: wrap。重要的是保持总计 100% width 每行包括 5 个盒子。如果你想给出不同的高度,你可以修改盒子的css代码

.day {
  color: white;
  margin: 1%;
}

.calendar {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  width: 100%;
  height: 586px;
}

.day1 {
  width: 28%;
  height: 200px;
  background: lightblue;
}

.day2 {
  width: 8%;
  height: 200px;
  background: orange;
}

.day3 {
  width: 28%;
  height: 200px;
  background: lightcoral;
}

.day4 {
  width: 8%;
  height: 200px;
  background: lightgray;
}

.day5 {
  width: 18%;
  height: 200px;
  background: lightblue;
}

.day6 {
  width: 18%;
  height: 200px;
  background: lightsteelblue;
}

.day7 {
  width: 18%;
  height: 200px;
  background: lightblue;
}

.day8 {
  width: 18%;
  height: 200px;
  background: lightsteelblue;
}

.day9 {
  width: 18%;
  height: 200px;
  background: orange;
}

.day10 {
  width: 18%;
  height: 200px;
  background: cyan;
}

.day11 {
  width: 38%;
  height: 200px;
  background: lightcoral;
}

.day12 {
  width: 8%;
  height: 200px;
  background: lightgray;
}

.day13 {
  width: 18%;
  height: 200px;
  background: lightcyan;
}

.day14 {
  width: 8%;
  height: 200px;
  background: orange;
}

.day15 {
  width: 18%;
  height: 200px;
  background: lightcoral;
}
<div class="calendar">
  <div class="day day1">1</div>
  <div class="day day2">2</div>
  <div class="day day3">3</div>
  <div class="day day4">4</div>
  <div class="day day5">5</div>
  <div class="day day6">6</div>
  <div class="day day7">7</div>
  <div class="day day8">8</div>
  <div class="day day9">9</div>
  <div class="day day10">10</div>
  <div class="day day11">11</div>
  <div class="day day12">12</div>
  <div class="day day13">13</div>
  <div class="day day14">14</div>
  <div class="day day15">15</div>
</div>

【讨论】:

  • 和给我写@Azu一样,高度都是一样的。
猜你喜欢
  • 2023-03-22
  • 1970-01-01
  • 2013-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-31
  • 2015-12-22
相关资源
最近更新 更多