2

I am trying to achieve the following layout: a grid with several columns of fixed width, one of which has content of unknown width, which will consist of multiple span elements, will not wrap, and has to be truncated with an ellipsis.

enter image description here

A more concrete example:

enter image description here

Here's what I tried, unsuccessfully, using a flexbox:

.grid {
  width: 300px;
  border: 1px solid black;
  display: grid;
  grid-template-columns: [main] minmax(0, 1fr) [foo] 20px [bar] 20px
}

main {
  grid-column: main;
  white-space: nowrap;
  background: yellow;
}

.color-marker {
  height: 10px;
  width: 10px;
  background: red;
  border-radius: 50%;
}

.test {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

.test > * {
  flex: 0 0 auto;
}


.foo {
  grid-column: foo;
  height: 20px;
  width: 20px;
  background-color: orange;
}

.bar {
  grid-column: bar;
  height: 20px;
  width: 20px;
  background-color: purple;
}
<div class="grid">
  <main>
    <div class="test">
      <div class="color-marker"></div>
      
      <span>
        Lorem ipsum
      </span>

      <span>
        sed do eiusmod tempor incididunt ut labore
      </span>

    </div>
  </main>
  <div class="foo">
  </div>
  <div class="bar">
  </div>
</div>

same example on jsbin

I also tried to use an inline grid instead of a flexbox, which didn't help either (example on jsbin).

Is there a way to make this work?

Disclaimer: I realise that variants of this question have been asked on Stack Overflow; but none of the suggested solutions worked for me. Here are the threads that I have examined:

I hope this doesn't make my question a duplicate.

azangru
  • 2,644
  • 5
  • 34
  • 55

4 Answers4

1

As a start, see if this meets your needs. See code comments for changes made.

EDIT: Now either span, but only 1 span, will cause ellipsis.

EDIT 2: This does not cause the ellipsis to inherit the color of one of the spans. The ellipsis color can be set independently in .spanContainer.

.grid {
  width: 300px;
  border: 1px solid black;
  display: grid;
  grid-template-columns: [main] minmax(0, 1fr) [foo] 20px [bar] 20px
}

main {
  grid-column: main;
  white-space: nowrap;
  background: yellow;
}

.color-marker {
  height: 10px;
  width: 10px;
  background: red;
  border-radius: 50%;
  align-self: center;       /*<------------ added */
  flex: 1 0 auto;           /*<------------ added */
}

.test {
  display: flex;            
  justify-content: flex-start;  /*<------------ changed */
}

/* .test > * {                <------------ removed
  flex: 0 0 auto;
} */

.spanContainer {            /*<------------ added */
  overflow: hidden;         /*<------------ added */
  white-space: nowrap;      /*<------------ added */
  text-overflow: ellipsis;  /*<------------ added */
  width: 100%;              /*<------------ added */
  color: purple;            /*<------------ added set ellipsis color here*/
}

.foo {
  grid-column: foo;
  height: 20px;
  width: 20px;
  background-color: orange;
}

.bar {
  grid-column: bar;
  height: 20px;
  width: 20px;
  background-color: purple;
}

.span1 {
  color: red;
  font-size: 1rem;
}

.span2 {
  color: green;
  font-size: 0.5rem;
}
<div class="grid">
  <main>
    <div class="test">
      <div class="color-marker"></div>
      <div class="spanContainer">
        <span class="span1">
          Lorem ipsum
        </span>

        <span class="span2">
          sed do eiusmod tempor incididunt ut labore sed do eiusmod tempor incididunt ut labore
        </span>
      </div>
    </div>
  </main>
  <div class="foo">
  </div>
  <div class="bar">
  </div>
</div>
Rob Moll
  • 3,345
  • 2
  • 9
  • 15
  • The reason I used several spans is because they can be formatted differently (different font-size, etc.); but they should behave as a single line, i.e. the truncation should only start at the span that overflows the parent wrapper. In your example, the span containing "Lorem ipsum" is also truncated. This won't work for my case. – azangru Nov 02 '21 at 13:55
  • @azangru - See the edit. – Rob Moll Nov 02 '21 at 14:41
  • A-ha, this is better. I believe it will suffer from the same problem as my answer below (https://stackoverflow.com/a/69812073/3925302), namely that if the truncated span has a different style than the parent, the ellipsis will still have the style of the parent. – azangru Nov 02 '21 at 15:08
  • @azangru - It does not suffer from the problem you mentioned. I made another edit to demonstrate. – Rob Moll Nov 02 '21 at 15:34
  • Sorry for being unclear. What I mean is that, by necessity, it applies to the ellipsis the style of the container component (called `spanContainer` in your example). Whereas, as a human reader, you would expect the ellipsis to have the same style as the text of the child that happens to be truncated :-( – azangru Nov 02 '21 at 15:46
0

I provide some example:

.grid {
  width: 300px;
  border: 1px solid black;
  display: inline-grid;
  grid-template-columns: [main] minmax(0, 1fr) [foo] 20px [bar] 20px;
   overflow: hidden;
}

main {
  grid-column: main;
  white-space: nowrap;
  background: yellow;
}

.color-marker {
  height: 10px;
  width: 10px;
  background: red;
  border-radius: 50%;
}

.foo {
  grid-column: foo;
  height: 20px;
  width: 20px;
  background-color: orange;
}

.bar {
  grid-column: bar;
  height: 20px;
  width: 20px;
  background-color: purple;
}

.test {
    display: flex;   
     align-items: baseline;
      gap: 0.2rem;
}
.l {
    width: 10%;
    flex-shrink: 1;
    display: flex;
}

.m-content {    
    text-align: center;
}

.color-marker {
  height: 10px;
  width: 10px;
  background: red;
  border-radius: 50%;
}
<!DOCTYPE html>
<html>

  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>JS Bin</title>
  </head>

  <body>
    <div class="grid">
      <main>
        <div class="test">
          <div class="l">
            <div class="color-marker"></div>
          </div>
          <div class="m">
            <div class="m-content">
              <span>
                Lorem ipsum
              </span>
              <span>
                sed do eiusmod tempor incididunt ut labore
              </span></div>
          </div>
        </div>
      </main>
      <div class="foo">
      </div>
      <div class="bar">
      </div>
    </div>

  </body>

</html>
Andrew
  • 572
  • 6
  • 29
0

I'll just post a baseline solution that I would love to improve. It has obvious drawbacks. And it's also kind of cheating the question, because it's backing away from the flexbox and using a simple display: block. On the plus side, it can truncate the text in the spans. On the minus side, however, if a child span has a style that is distinctive from the parent, the ellipsis will still have the style of the parent (seen in the example below through the use of red and black colors).

Is there a way to make this better?

.grid {
  width: 300px;
  border: 1px solid black;
  display: grid;
  grid-template-columns: [main] minmax(0, 1fr) [foo] 20px [bar] 20px
}

main {
  grid-column: main;
  white-space: nowrap;
  background: yellow;
}

.color-marker {
  display: inline-block;
  height: 10px;
  width: 10px;
  background: red;
  border-radius: 50%;
}

.test {
  overflow: hidden;
  text-overflow: ellipsis;
  color: red;
}

.text-secondary {
  font-size: 10px;
  color: grey;
}

.foo {
  grid-column: foo;
  height: 20px;
  width: 20px;
  background-color: orange;
}

.bar {
  grid-column: bar;
  height: 20px;
  width: 20px;
  background-color: purple;
}
<div class="grid">
  <main>
    <div class="test">
      <div class="color-marker"></div>
      
      <span>
        Lorem ipsum
      </span>

      <span class="text-secondary">
        sed do eiusmod tempor incididunt ut labore
      </span>

    </div>
  </main>
  <div class="foo">
  </div>
  <div class="bar">
  </div>
</div>
azangru
  • 2,644
  • 5
  • 34
  • 55
0

We can use increasing flex-shrink on spans. Following is the minimal working example with three span:

<html>

<head>
  <script>
    function changeWidth(newWidth) {
      document.getElementById("test").style.width = newWidth;
    }
  </script>
  <style media="all">
    .color-marker {
      height: 10px;
      width: 10px;
      background: red;
      border-radius: 50%;
      display: inline-block;
    }
    
    .test {
      background: yellow;
      align-items: baseline;
      width: 200px;
      white-space: nowrap;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    
    .test span {
      color: red;
    }
    
    .test :nth-child(1) {
      flex-shrink: 0;
    }
    
    .test :nth-child(2) {
      flex-shrink: 1;
    }
    
    .test :nth-child(3) {
      flex-shrink: 1800;
    }
    
    .test :nth-child(4) {
      flex-shrink: 7020000;
    }
  </style>
</head>

<body>
  Slide to change width:
  <input type="range" id="shrinker" min="50" max="400" value="200" oninput="changeWidth(this.value);" />
  <br />
  <br />
  <div id="test" class="test">
    <div class="color-marker"></div>
    <span> One One One One </span>
    <span> Two Two Two</span>
    <span> Hree Hree Hree</span> Four Four
  </div>
</body>

</html>

I don't know why the output is not interactive on stackoverflow. If you put it in local html file and use the slider you can change width of the test div.
OR Use "Run with JS" option: https://jsbin.com/fabapowumo/edit?html,output

Note: This works on chrome and edge. Don't know about other browsers.

the Hutt
  • 16,980
  • 2
  • 14
  • 44