首页 > 解决方案 > 无媒体查询如何实现3列桌面转1列移动布局

问题描述

在这里查看了几个问题,但它们并不能完全解决我正在寻找的问题。

假设我有一个网站并且我想要。在桌面上我想要这个:

在此处输入图像描述

这很简单。grid-template-columns: repeat(3, 33%)(基本上)

但是,在移动设备上,我想要这个

在此处输入图像描述

我遇到的是在它翻转到单列之前发生的事情:

在此处输入图像描述

我正在尝试clamp(),minmax()和各种各样的东西,但没有任何东西能按我的意愿工作。是的,我完全可以使用媒体查询,但我希望使用现代 CSS(如钳位、网格、最小最大值等)创建真正流畅的网格/弹性布局,这样就不需要媒体查询来更改基本布局。

我知道这不起作用,但作为起点,这里是我的 100 次尝试之一的简单版本:) 在这个版本中,我试图使用钳位从重复 (3) 切换到重复 (1)。

.wrapper {
  display: grid;
  gap: 15px;
  grid-template-columns: repeat(clamp(1, calc(100% - 500px), 3), 33%);
}

.one {
  background: red;
}

.two {
  background: green;
}

.three {
  background: blue;
}
<div class="wrapper">
  <div class="item one"><h3>Example A</h3></div>
  <div class="item two"><h3>Example Two</h3></div>
  <div class="item three"><h3>Third Example</h3></div>
</div>

标签: cssflexboxcss-grid

解决方案


这是一个使用max(0px, (400px - 100vw)*1000)内部 flex-basis 的想法。0px如果100vw(屏幕尺寸)大于400px或非常大的值,则此公式将给出相反的情况,给每个元素一个大flex-basis并创建一个包装。只需调整400px其中发挥的作用@media (max-width:400px)

.container {
  display:flex;
  flex-wrap:wrap;
}

.container div {
  height:100px;
  border:2px solid;
  background:red;
  flex-basis:max(0px, (400px - 100vw)*1000);
  flex-grow:1;
}
<div class="container">
  <div></div>
  <div></div>
  <div></div>
</div>

使用 CSS 网格可以如下所示:

.container {
  display:grid;
  grid-template-columns:repeat(auto-fill,minmax(clamp(30%, (400px - 100vw)*1000, 100%),1fr));
  grid-gap:5px;
}

.container div {
  height:100px;
  border:2px solid;
  background:red;
}
<div class="container">
  <div></div>
  <div></div>
  <div></div>
</div>

一个类似的问题,我正在控制没有媒体查询的最大列数:CSS grid maximum number of columns without media queries


我们可以扩展上述解决方案以考虑更复杂的情况。

从 6 列移动到 3 列再到 1 列的示例:

.container {
  display:grid;
  grid-template-columns:
    repeat(auto-fill,
      minmax(clamp(clamp(15%,(800px - 100vw)*1000, 30%), (400px - 100vw)*1000, 100%)
      /* if(screen> 800px) 15% elseif(screen> 400px) 30% else 100% */
      ,1fr));
  grid-gap:5px;
}

.container div {
  height:100px;
  border:2px solid;
  background:red;
}
<div class="container">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>

要了解这些值,请考虑以下范围:

100%/7  100%/6  100%/5  100%/4  100%/3  100%/2  100%/1
 14.3%  16.7%    20%     25%     33.3%   50%     100%

要获得 6 列,我们需要范围内的值]14.3% 16.7%](我考虑过15%) 要获得 3 列,我们需要范围内的值]25% 33.3%](我考虑过30%

我们只是避免边缘以确保我们考虑到差距。

一个使用 CSS 变量的更通用的解决方案,我将在其中添加0.1%以确保该值足够大以获得所需的列数并且它可以保持差距。

让我们也添加一些动态着色(相关:如何根据高度或宽度改变 <div> 元素的颜色?

.container {
  /* first breakpoint*/
  --w1:800px;
  --n1:6;
  /* second breakpoint*/
  --w2:400px;
  --n2:3;

  display:grid;
  grid-template-columns:
    repeat(auto-fill,
      minmax(clamp(clamp(100%/(var(--n1) + 1) + 0.1%, (var(--w1) - 100vw)*1000,
                         100%/(var(--n2) + 1) + 0.1%), (var(--w2) - 100vw)*1000,
                         100%), 1fr));
  grid-gap:5px;
  margin:10px 0;
}

.container div {
  height:100px;
  border:2px solid;
  background:
    linear-gradient(blue  0 0) 0 /1% calc(var(--w2) - 100vw),
    linear-gradient(green 0 0) 0 /1% calc(var(--w1) - 100vw),
    red;
}
<div class="container">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>

<div class="container" style="--w1:900px;--n1:8;--w2:500px;--n2:4;grid-gap:10px;">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>

<div class="container" style="--w1:600px;--n1:4;--n2:2;grid-gap:2vw;">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>

使用 flexbox,我们可以有不同的(可能是想要的)行为,其中一行的最后一项将占用所有可用空间:

.container {
  /* first breakpoint*/
  --w1:800px;
  --n1:6;
  /* second breakpoint*/
  --w2:400px;
  --n2:3;

  display:flex;
  flex-wrap:wrap;
  margin:10px 0;
}

.container div {
  height:100px;
  border:2px solid;
  margin:5px;
  flex-basis:clamp(clamp(100%/(var(--n1) + 1) + 0.1% ,(var(--w1) - 100vw)*1000, 
                         100%/(var(--n2) + 1) + 0.1%),(var(--w2) - 100vw)*1000, 
                         100%);
  flex-grow:1;
  box-sizing:border-box;
  background:
    linear-gradient(blue  0 0) 0 /1% calc(var(--w2) - 100vw),
    linear-gradient(green 0 0) 0 /1% calc(var(--w1) - 100vw),
    red;
}
<div class="container">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>

<div class="container" style="--w1:900px;--n1:8;--w2:500px;--n2:4;">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>

<div class="container" style="--w1:600px;--n1:4;--n2:2;">
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
  <div></div>
</div>


推荐阅读