0

I have a text-containing element where the text can be very long. I want to hide overflow text and I don't want the text to increase the size of the element or its parents/ancestors.

Adding the following to the element CSS seemed to work at first (from this question, but height not width):

      height: 0;
      min-height: 100%;

This works on Chrome; however, it doesn't quite seem to work on Safari (mobile or desktop). Here is an example:

side-by-side comparison of Chrome and Safari

The image shows a side-by-side comparison of Chrome (left) and Safari (right). The text should be vertically centered but as can be seen, the Safari text is not. Eventually, if the page height gets too small, the text disappears completely.

The HTML is at the foot of this post (sorry I couldn't get it shorter). Inspecting via devtools on Chrome (Version 88.0.4324.146) and Safari (Version 13.1.3), both on a Mac, the problem seems to be that the inner element is oversized on Safari. This seems to be directly caused by the height:0;min-height:100% trick, in that replacing these lines with height:100% causes the centering problem to go away in Safari (but then the layout is perturbed in Chrome when the text is longer).

As I understand it, the min-height:100% should set the inner element's height to the height of the containing block, which (since inner has position:relative and its parent card has display:flex), should be the content box of the parent card element, as described here.

This appears to work as described in Chrome, but not Safari. I am not sure where Safari is getting the height of the inner element from, but it's clearly taller than card.

For context, here is what the original problem that I was having looks like (layout messed up in Chrome when there's a lot of text in the cyan box). This is the problem that I was trying to solve with the height:0;min-height:100%. For this screenshot I removed those lines and just put height:100%. Here's what that looks like (again, Chrome on left and Safari on right)

Chrome vs Safari, layout messed up by long text

As you can see, the orange box has disappeared in Chrome (left). Adding the height:0;min-height:100% back in causes this to render correctly (but with the problem described above, that the text is not vertically centered in Safari - it looks centered here, but that's only because the overflow is hidden so the card appears full of text):

correct layout of long text

Any insights appreciated. Is this just a bug in Safari? Is there a workaround? Or (more likely) am I just a CSS klutz...

Update: here's what it looks like in Safari devtools. The parent card element has height 938px, but the inner has height 1121px and pushes the bottombar off the screen.

Safari devtools

<html>
  <head>
    <style>
      html, body {
      height: 100%;
      overflow: hidden;
      margin: 0;
      padding: 0;
      }

      body {
      position: relative;
      }

      .page {
      background: midnightblue;

      width: 100%;
      height: 100%;
      display: flex;
      flex-direction: row;
      justify-content: center;
      }

      .central-column {
      display: flex;
      flex-direction: column;
      }

      .bottombar {
      background: orange;

      height: 80px;
      z-index: 30;
      display: flex;
      flex-direction: column;
      justify-content: space-around;

      font-size: 2vh;
      text-align: center;
      }

      .foo {
      background: pink;
      position: relative;
      flex-grow: 1;

      display: flex;
      flex-direction: column;
      }

      .foo,
      .central-column {
      width: 800px;
      max-width: 800px;
      height: 100%;
      }

      .foo .topbar {
      background: red;
      position: relative;
      display: flex;
      flex-direction: row;
      justify-content: space-around;
      min-height: 90px;
      height: 15vh;
      max-height: 90px;
      }

      .foo .cardbar {
      position: relative;
      
      flex-grow: 1;
      display: flex;
      flex-direction: column;

      padding: 4px 20px;
      }

      .foo .cardtable {
      background: green;
      
      position: relative;

      flex-grow: 1;
      display: flex;
      flex-direction: column;

      padding: 4px;
      }

      .foo .stack {
      flex-grow: 1;
      display: flex;
      flex-direction: column;
      justify-content: space-around;
      z-index: 6;
      position: relative;
      padding: 4px 20px;
      }

      .foo .stack .card {
      background: cyan;
      position:relative;
      max-height: 160vw;
      flex-grow: 1;
      display: flex;
      flex-direction: column;
      overflow: hidden;
      border-radius: 2vh;
      border-width: 1px;
      border-style: solid;
      }

      .foo .stack .card .inner {

      position: relative;
      display: flex;
      flex-direction: column;
      justify-content: space-evenly;

      height: 0;
      min-height: 100%;
/*
  Replacing the previous two lines with this line fixes the centering on Safari,
  but then longer text (that would overflow the cyan box) breaks the layout in Chrome

      height: 100%;
*/
      
      text-align: center;
      overflow: hidden;

      margin: 4px;
      }
    </style>
  </head>

  <body>
    <div class="page">
      <div class="central-column">
    <div class="foo">
      <div class="topbar">
      </div>
      <div class="cardbar">
        <div class="cardtable">
          <div class="stack">
        <div class="card">
          <div class="inner">
            <div class="content">
              this text should be vertically centered in the cyan box
            </div>
          </div>
        </div>
          </div>
        </div>
      </div>
      <div class="bottombar"></div>
    </div>
      </div>
    </div>
  </body>

</html>
Ian Holmes
  • 149
  • 1
  • 11

1 Answers1

1

Here is a simplified example (I removed a couple elements from your code just to make it easier to read). The scroll element needs two things: a parent with overflow:hidden, and an ancestor with a height property (can't be auto). Then to center the non-overflowing content, just use flexbox on the parent, and margin:auto on the content element.

*** UPDATE

A better explanation of what is going on with your code:

  1. You want to center a content block while making the parent hide its overflow if any.
  2. For overflow to work it needs a parent with a height otherwise it will not know where to cut off the content.
  3. To vertically center the content box within the available space, set the parent to display:flex.
  4. The important part: the content block has to be centered using margin:auto otherwise when there is overflow, it will remain centered with its top and bottom parts being cut-off by the parent's overflow:hidden.

body,
html {
  margin: 0;
  padding: 0;
  height: 100%;
}

.page {
  /* Set height for overflow element ancestor */
  height: 100%;
  max-height: 100vh;
  display: flex;
  background: blue;
  justify-content: center;
}

.central-column {
  flex-basis: 100%;
  max-width: 90%;
  display: flex;
  flex-direction: column;
  height: 100%;
}

.topbar {
  height: 20%;
  flex-shrink: 0;
  background: red;
}

.cardbar {
  flex-grow: 1;
  display: flex;
  /* Parent of the scroll element hide overflow */
  overflow: hidden;
}

.cardtable {
  padding: 20px;
  background: white;
  display: flex;
  flex-basis: 100%;
}

.card {
  background: cyan;
  padding: 30px;
  /* Margin auto to center the content */
  margin: auto;
  text-align: center;
}

.bottombar {
  height: 20%;
  flex-shrink: 0;
  background: red;
}
<div class="page">
  <div class="central-column">
    <div class="topbar">
    </div>
    <div class="cardbar">
      <div class="cardtable">
        <div class="card">
          <div class="content">
            Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit.Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
          </div>
        </div>
      </div>
    </div>
    <div class="bottombar"></div>
  </div>
</div>

*** UPDATE 2

Here it is with your HTML.

body,
html {
  padding: 0;
  margin: 0;
  min-height: 100%;
}

.page {
  width: 100%;
  display: flex;
  justify-content: center;
  background: navy;
  height: 100vh;
}

.central-column {
  flex-basis: 100%;
  max-width: 900px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
}

.foo {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
  align-items: stretch;
  height: 100%;
}

.topbar,
.bottombar {
  height: 20%;
  background: coral;
  flex-shrink: 0;
}

.cardbar {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: 10px 20px;
  background: pink;
  flex-grow: 1;
  overflow: hidden;
}

.cardtable {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  padding: 10px 20px;
  background: forestgreen;
  flex-grow: 1;
  overflow: hidden;
}

.stack {
  border-radius: 10px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  background: lightblue;
  flex-grow: 1;
  overflow: hidden;
}

.card {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  flex-grow: 1;
}

.inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex-grow: 1;
}

.content {
  margin: auto;
  padding: 10px;
  text-align: center;
}
<div class="page">
  <div class="central-column">
    <div class="foo">
      <div class="topbar">
      </div>
      <div class="cardbar">
        <div class="cardtable">
          <div class="stack">
            <div class="card">
              <div class="inner">
                <div class="content">
                  this text should be vertically centered in the cyan box
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="bottombar"></div>
    </div>
  </div>
</div>
return_false
  • 659
  • 3
  • 7
  • Thank you; however, when I add the commented elements from your answer to my example, and run it on Safari, the text is still vertically uncentered. If possible could you use my example without removing elements? Side notes: (1) `margin:auto` on `card` does not seem to affect whether the content is centered, it just reduces the margins, which I did not want; and (2) it looks like you've added `overflow-y:scroll` to `cardtable`, and you also talked about "the scroll element"? I didn't want scrolling behavior. Having said this, I can't see any scrollbars so perhaps I am misunderstanding that. – Ian Holmes Feb 10 '21 at 05:34
  • I'm downvoting because this answer doesn't seem to work on my example, and apparently introduces extraneous styling (like the scrollbars) - sorry if this seems unjust, I would be happy to retract the downvote if you can amend the answer – Ian Holmes Feb 12 '21 at 19:41
  • Dude if you dont want the overflow to scroll then just remove that line from the code. I went ahead and removed it for you. You need the margin:auto on the element you want to center otherwise it will break when there is overflow. – return_false Feb 12 '21 at 21:38
  • The scrollbars aren't really the issue, the problem is that when I try to implement your suggestions within the code snippet I supplied, it (a) visibly shrinks the margins and (b) does not solve the centering problem on Safari. However I really appreciate the clarity of your explanations so, while I can't yet mark this answer as accepted (because it doesn't seem to solve the problem), I am upvoting it. Thank you! – Ian Holmes Feb 13 '21 at 02:59
  • Did this answer work for you? I updated it with your code. – return_false Feb 21 '21 at 15:08
  • Yes, it works, thanks! Marking your answer as correct. – Ian Holmes Feb 22 '21 at 17:12
  • 1
    Glad to hear it! Remember, the reason the container was not hiding the overflow, is because it did not have a height reference to know where to cut off the content. – return_false Feb 22 '21 at 17:15