Search code examples
htmlcssoverflowcss-grid

Maintain ratio between column in CSS grid. How grid-column is calculated?


I want my grid to maintain a certain ratio, but a long sentence increases the width of the grid it belongs to.

body {
  display: grid;
}

main {
  grid-column: 1 / 8;
  border: 2px solid black;
}

aside {
  grid-column: 8 / 13;
  border: 2px solid black;
}
<main>
  <p>Mauris neque quam, fermentum ut nisl vitae, convallis maximus nisl. Sed mattis nunc id lorem euismod placerat. Vivamus porttitor magna enim, ac accumsan tortor cursus at. Phasellus sed ultricies mi non congue ullam corper. Praesent tincidunt sed tellus
    ut rutrum. Sed vitae justo condimentum, porta lectus vitae, ultricies congue gravida diam non fringilla.</p>
</main>
<aside>
  <p>Aside</p>
</aside>

I tried using "word-wrap: break-word", "word-break: break-all", "white-space: normal", "overflow-wrap: break-word", "overflow: hidden", but none of them worked.

How do I have the text either wrap within the grid or have the overflow hidden?


Solution

  • This is a logical behavior and you simply need to understand how the different sizes are calculated and considering you configuration there will be no ratio.

    Let's start with an easy example:

    .container {
      display: grid;
    }
    
    main {
      grid-column: 1 / 8;
      border: 2px solid black;
    }
    <div class="container">
      <main>
        <p>Mauris neque quam, .</p>
      </main>
    </div>

    We have defined a grid-column:1/8 thus we will implicitely have 7 columns and the size of each one will be calculated based on the content. In this case, it's trivial as we will have the same size of each column. Basically we didn't specify that our grid need to have 7 columns or that they all need to have the same size. This was implicitely defined.

    This implicit grid will later be used to place other elements:

    .container {
      display: grid;
    }
    
    main {
      grid-column: 1 / 8;
      border: 2px solid black;
    }
    .container > div {
      background:red;
      height:50px;
    }
    <div class="container">
      <main>
        <p>Mauris neque quam, .</p>
      </main>
      <div></div>
    </div>

    As you can see, the red div will be placed on the first column defined previously.

    Now let's add another element:

    .container {
      display: grid;
    }
    
    main {
      grid-column: 1 / 8;
      border: 2px solid black;
    }
    
    aside {
      grid-column: 8 / 13;
      border: 2px solid black;
    }
    <div class="container">
      <main>
        <p>Mauris neque quam,</p>
      </main>
      <aside>
        <p>A</p>
      </aside>
    </div>

    This is a more complex situation where will have a total number of columns equal to 12 and not all of them are equal size:

    enter image description here

    The calculation done here is somehow complex 1 and depends on the content. If we refer to the specification:

    Once the grid items have been placed, the sizes of the grid tracks (rows and columns) are calculated, accounting for the sizes of their contents and/or available space as specified in the grid definition.

    We did specify nothing in the grid definition so only the content size will decide here. You can clearly notice this if you simply change the content without the need of using long sentences:

    .container {
      display: grid;
    }
    
    main {
      grid-column: 1 / 8;
      border: 2px solid black;
    }
    
    aside {
      grid-column: 8 / 13;
      border: 2px solid black;
    }
    <div class="container">
      <main>
        <p>Mauris neque quam, .</p>
      </main>
      <aside>
        <p>A</p>
      </aside>
    </div>
    <div class="container">
      <main>
        <p>Mauris neque quam, .</p>
      </main>
      <aside>
        <p>ABC</p>
      </aside>
    </div>
    <div class="container">
      <main>
        <p>Mauris</p>
      </main>
      <aside>
        <p>A</p>
      </aside>
    </div>
    <div class="container">
      <main>
        <p>Mauris neque quam  .</p>
      </main>
      <aside>
        <p>A Mauris Mauris</p>
      </aside>
    </div>
    <div class="container">
      <main>
        <p>A Mauris Mauris</p>
      </main>
      <aside>
        <p>A Mauris Mauris</p>
      </aside>
    </div>

    Each time we used a different content and each time we obtain a different size.

    To avoid this you need to explicitely define the size of your grid. In your case, you want to have 12 columns with the first item taking 7 and the second one 5. You can simply do like this:

    .container {
      display: grid;
      grid-template-columns:7fr 5fr;
    }
    
    main {
      border: 2px solid black;
    }
    
    aside {
      border: 2px solid black;
    }
    <div class="container">
      <main>
        <p>Mauris neque quam, .</p>
      </main>
      <aside>
        <p>A</p>
      </aside>
    </div>
    <div class="container">
      <main>
        <p>Mauris neque quam, .</p>
      </main>
      <aside>
        <p>ABC</p>
      </aside>
    </div>
    <div class="container">
      <main>
        <p>Mauris</p>
      </main>
      <aside>
        <p>A</p>
      </aside>
    </div>
    <div class="container">
      <main>
        <p>Mauris neque quam  .</p>
      </main>
      <aside>
        <p>A Mauris Mauris</p>
      </aside>
    </div>
    <div class="container">
      <main>
        <p>A Mauris Mauris</p>
      </main>
      <aside>
        <p>A Mauris Mauris</p>
      </aside>
    </div><div class="container">
      <main>
        <p>A Mauris Mauris A Mauris Mauris A Mauris Mauris A Mauris Mauris A Mauris Mauris A Mauris MaurisA Mauris Mauris A Mauris Mauris A Mauris MaurisA Mauris Mauris A Mauris Mauris A Mauris MaurisA Mauris Mauris A Mauris Mauris A Mauris MaurisA Mauris Mauris A Mauris Mauris A Mauris Mauris</p>
      </main>
      <aside>
        <p>A Mauris Mauris</p>
      </aside>
    </div>


    1 Let's take an easy example to have an idea how the calculation is done:

    .container {
      display: grid;
      width:600px;
    }
    
    main {
      grid-column: 1 / 3;
    }
    main > div {
      width:50px;
      height:50px;
      background:red;
    }
    
    aside {
      grid-column: 3/ 4;
    }
    aside > div {
      width:100px;
      height:50px;
      background:green;
    }
    <div class="container">
      <main>
        <div></div>
      </main>
      <aside>
        <div></div>
      </aside>
    </div>

    In this example, we have a grid width equal to 600px, the first element 50px and the second one 100px we will have a free space of 450px. The implicit grid contain 3 columns, so we split this space into 3. One portion will got to the aside (100px + 150px = 250px) thus we will have a column equal to 250px containing an element equal to 100px. The two other portions will go to main (50px + 2*150px = 350px) thus will have each column equal to 175px.

    enter image description here

    Let's do the opposite. what should be the size of our divs in order to obtain the same column sizes?

    Based on the previous calculation the formula is like below:

    Ca (aside column) = (Dx + F/3)
    Cm (main column) = (Dy + 2*F/3)/2
    

    F is our free space defined by (W - Dx - Dy) where W is the container width. Now we want to have Ca = Cm and after some math stuff we will have.

    Dx = Dy/2
    

    So we simply need to make the first div twice bigger than the second one:

    .container {
      display: grid;
      width:600px;
    }
    
    main {
      grid-column: 1 / 3;
    }
    main > div {
      width:calc(2*var(--s));
      height:50px;
      background:red;
    }
    
    aside {
      grid-column: 3/ 4;
    }
    aside > div {
      width:var(--s);
      height:50px;
      background:green;
    }
    <div class="container" style="--s:50px">
      <main >
        <div></div>
      </main>
      <aside>
        <div></div>
      </aside>
    </div>
    <div class="container" style="--s:100px">
      <main >
        <div></div>
      </main>
      <aside>
        <div></div>
      </aside>
    </div>
    <div class="container" style="--s:120px">
      <main >
        <div></div>
      </main>
      <aside>
        <div></div>
      </aside>
    </div>
    <div class="container" style="--s:200px">
      <main >
        <div></div>
      </main>
      <aside>
        <div></div>
      </aside>
    </div>

    enter image description here

    You can clearly notice that all the grids have the same column size (200px in this case) if we respect the relation between both content. Now you can scale this calculaion to your real example and you will better understand.

    By the way, you example is a particular case, since you have no free space so the size of the column in main will be the size of its content divided by 7 and the one of aside will be the size of its content divided by 5.

    enter image description here