search

Home  >  Q&A  >  body text

3-column desktop to 1-column mobile layout without media queries

There are some questions looked at here, but they don't quite solve the problem I'm looking for.

Suppose I have a website and I want to. On the desktop I want this:

It's easy. grid-template-columns: Repeat (3, 33%) (Basically)

But, on a mobile device, I want this

What I encountered happened before it flipped to a single column:

I'm trying clamp(), minmax() and all kinds of stuff, but nothing is working the way I want. Yes, I could definitely use media queries, but I'd like to create a truly fluid grid/flex layout using modern CSS (like clamp, grid, minmax, etc.) so that no media queries are needed to make basic layout changes. < /p>

I know this doesn't work, but as a starting point for the request, here's a simple version of one of my 100 attempts :) In this version I try to switch from repeat(3) to repeat(1) using clamp ).

.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>

P粉085689707P粉085689707340 days ago527

reply all(1)I'll reply

  • P粉070918777

    P粉0709187772023-12-24 11:12:44

    Full article with more general rules: https:// css-tricks.com/responsive-layouts-fewer-media-queries/

    Here's an idea to use max(0px, (400px - 100vw)*1000) in flex-basis. If 100vw (screen size) is greater than 400px, this formula will give 0px, or in the opposite case a very large value for each element provides a big flex-basis and creates a wrapper. Just adjust 400px to play @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>

    Using CSS Grid, it can look like this:

    .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>

    A similar question where I control the maximum number of columns without media queries: CSS Grid - Maximum number of columns without media queries< /a>


    We can extend the above solution to consider more complex cases.

    Example of moving from 6 columns to 3 columns to 1 column:

    .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>

    To understand these values, consider the following ranges:

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

    To get 6 columns we need values ​​in the range ]14.3% 16.7%] (I'm considering 15%) To get 3 columns we need values ​​in the range ]25% 33.3%] (I was thinking 30%)

    We just avoid the edges to make sure we account for the gaps.

    A more general solution using CSS variables, where I would add 0.1% to ensure the value is large enough to get the desired number of columns and can accommodate the gaps.

    We also add some dynamic coloring (related: How to change the color of an

    element based on its height or width? < /a>)

    .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>

    Using flexbox we can have a different (possibly desired) behavior where the last item of a row will take up all available space:

    .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>

    reply
    0
  • Cancelreply