Search code examples
htmlcsscss-grid

CSS grid auto column does not break text


TL;DR: I had achieved the styling I needed using devtools, did not transfer it to the code right away and now cant for the life of me figure out why its not working.

I'm trying to achieve the following styling, the red block is an image I blocked for the sake of posting here. Its important that the title on the left and the text block on the right have the same size (basically the minimum width of the title) and the image takes the rest of the width.

I'm grateful for any help pushing me into the right direction, thanks in advance!

What I expect:

Styling I had and need again

I had achieved it using grid-template-columns: auto 1fr auto, as you can see in the above screenshot it was working but as mentioned in the tldr my dumbass forgot to transfer the devtools changes to the code...

As soon as I try putting the grid-template-columns as "auto 1fr auto" and adjust the grid-column-start of texts and image accordingly, I get this result:

Styling I currently get

As you can see, the image disappears completely and the text doesnt wrap to fit the same width as the title anymore and I cannot for the life of me figure out why...

Edit: Here is a little sandbox basically showing the problem I'm running into, I tried to make it as minimal but still showing the problem as possible: https://codesandbox.io/p/sandbox/happy-sanderson-2qlrs7

Edit 2: I just realized that in my expected screenshot it's not the same width between the title and textblock, but very similiar. Now my next question: is there a way to have them have the same width or should I set them using JS?


Solution

  • There is no CSS declaration available to set the width of a grid column to match the width of another specified column. For column 1, max-content would give you the desired width, but there is no way to specify that column 3 should match the width of column 1. You can’t create this design declaratively with either grid or flexbox.

    So you need to do it with Javascript, and I would use flexbox instead of grid to keep things simple.

    1. Create a hidden element elsewhere in your document containing the same text as your title. (Use position: absolute so it won’t affect the positioning of anything else, and then when you’ve got everything working, add display: none to hide it.)
    2. Measure the width of this element.
    3. Set the width of the first and last flex item to that measurement.

    A snippet to demonstrate:

    const titleWidth = document.getElementById('measure-this').offsetWidth + 'px'
    document.getElementById('width-is').innerHTML = titleWidth
    document.querySelector('.d2>*:first-child').style.width = titleWidth
    document.querySelector('.d2>*:last-child').style.width = titleWidth
    .d1 {
      margin-bottom: 2em;
      border: 3px dashed red;
      padding: 1em;
      opacity: 0.4;
    }
    
    .d2 {
      display: flex;
      gap: 5px;
    }
    
    .d2>* {
      background: silver;
    }
    
    .d2>*:nth-child(2) {
      flex: 1;
      text-align: center;
    }
    
    #measure-this {
      background: pink;
    }
    
    .title {
      font-size: 1.6em;
      font-weight: bold;
      color: blue;
      text-transform: uppercase;
    }
    <div class="d1">
      <span id="measure-this" class="title">über mich</span> is <span id="width-is"></span> wide.
    </div>
    
    <div class="d2">
      <div class="title">über mich</div>
      <div>centre column</div>
      <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas tempor nunc mauris, sit amet placerat tortor lobortis dapibus. Nam lectus eros, maximus ac magna vel, congue consequat eros. Fusce id pretium diam. Cras sit amet pharetra ante. Sed quis commodo quam, vel facilisis ipsum. Vestibulum sodales iaculis arcu, et fringilla nisi ullamcorper sed. Donec interdum sit amet est non accumsan. Donec non augue feugiat, fermentum nunc non, convallis est.</div>
    </div>