6

I have a list with some resizing elements. When the elements are resized, they should overflow the container in the x direction. There should never be scrolling in the x direction. Scrolling should be enabled in the y direction.

I have tried setting:

overflow-x: visible;
overflow-y: scroll;

But this seems to enable scrolling in both directions.

How do I prevent this?

https://jsfiddle.net/64tw8rqe/


The answers to CSS overflow-x: visible; and overflow-y: hidden; causing scrollbar issue explain the underlying problem but not a work-around in the case of scroll.


This behaviour is in accordance with the spec. I am looking for work-arounds.

Community
  • 1
  • 1
sdgfsdh
  • 33,689
  • 26
  • 132
  • 245
  • Possible duplicate of [CSS overflow-x: visible; and overflow-y: hidden; causing scrollbar issue](http://stackoverflow.com/questions/6421966/css-overflow-x-visible-and-overflow-y-hidden-causing-scrollbar-issue) – andreas Aug 05 '16 at 15:03
  • Is the x direction supposed to scroll when .messages is hovered over? – Luke Aug 05 '16 at 15:05
  • No. The message should go outside and over the container, like when scroll is disabled in both x and y. – sdgfsdh Aug 05 '16 at 15:06
  • 1
    The closest solution I've found is in this [CSS Trick](https://css-tricks.com/popping-hidden-overflow/) – Hunter Turner Aug 05 '16 at 15:12

5 Answers5

7

The problem is that overflow-x: visible; overflow-y: scroll is an impossible combination in CSS. Whenever visible is paired with scroll, it is converted to auto.

In other words, these are equivalent:

overflow-x: visible;
overflow-y: scroll;

overflow-x: auto;
overflow-y: scroll;

Perhaps it was a poor decision for the spec, but there are work-arounds.

By making the expanding elements position: absolute, their size will not change the container, and they will not be clipped by overflow: hidden. To get them positioned correctly, an extra div with position: relative is wrapped around the whole container.

HTML:

<div class='container1'>
  <div class='container2'>
    <ul class='messages'>
      <li><pre>Hello</pre></li>
      <li>
        <pre>This is a 
      really really really 
      really really long message.</pre>
      </li>
      <li><pre>World</pre></li>
    </ul>
  </div>
</div>

CSS:

* {
  margin: 0;
  padding: 0;
}

.container1 {
  position: relative; 
  width: 200px;
}

.container2 {
  background: #f0f;
  width: 100%;
  height: 100%;
  overflow: scroll;
}

.messages {
  overflow: visible;
  list-style: none;
}

.messages li {
  background: #ff0;
  width: 100%;
  height: 24px;
  margin-top: 12px;
}

.messages li pre {
  position: absolute;
  display: inline-block;
  box-sizing: border-box;
  width: 100%;
  max-height: 24px;
  padding: 4px;
  background: #0ff;
  border-radius: 4px;
  line-height: 16px;
  overflow: hidden;
  text-overflow: ellipsis;
  width: auto;
  min-width: 100%;
  max-width: 100%;
  transition: max-width 200ms ease-out, height 200ms ease-out;
}

.messages li pre:hover {
  z-index: 1;
  background: #00f;
  max-width: 80vw;
  max-height: 80vh;
  transition: max-width 200ms ease-in, max-height 200ms ease-in;
}

Fiddle: https://jsfiddle.net/cyL6tc2k/2/

Credit to the trick found here: http://front-back.com/how-to-make-absolute-positioned-elements-overlap-their-overflow-hidden-parent

sdgfsdh
  • 33,689
  • 26
  • 132
  • 245
  • I'm seeing 2 scrollbars in your jsfiddle. I tried changing container2 to have overflow: hidden but it didn't help. Any ideas on how to hide the scrollbars? – kahlan88 Oct 26 '22 at 17:24
1

When you have vertical overflow, a scrollbar is added to the horizontal flow (to the right). Elements will not overlay that scrollbar so browsers change your overflow settings to scroll horizontally instead.

What you will need to do is add another container around all of the content and set it to have a greater width that all of the overflowed content inside but a height of the inner element and vertical scroll:

HTML

<div class='container3'><!-- Add a parent container -->
  <div class='container'>
    ...
  </div>
</div>

CSS

/* A parent container */
.container3 {
  /* The maximum height of your inner content before scrolling is enabled */
  height: 200px;

  /* Enable the vertical scroll if we have enough content */
  overflow-y: auto;
}

FIDDLE

https://jsfiddle.net/cL8hr7ot/

Godwin
  • 9,739
  • 6
  • 40
  • 58
  • This does not solve the problem. It only makes the container so big that the contents do not trigger scrolling. – sdgfsdh Aug 05 '16 at 15:20
  • Vertical scrolling is triggered, I thought you didn't want horizontal scrolling? – Godwin Aug 05 '16 at 15:22
  • I don't want horizontal scrolling. The problem is that the solution requires a container wide enough to fit the content. What if I have another element positioned next to it? – sdgfsdh Aug 05 '16 at 15:27
  • You'll need to work out a solution using positioning and z-index, but in that case, where do you expect the scrollbar to be? That layout would be very confusing. The browser won't overlay your content on top of a scrollbar so you can only move it further right. – Godwin Aug 05 '16 at 15:32
0

This is due to your usage of "pre", which has some default values on some browsers :

    pre {
       display: block;
       font-family: monospace;
       white-space: pre;
       margin: 1em 0;
    }

You have two options : change all the "pre" by "p" (paragraph) or rewrite the white-space property of pre, by adding this :

    pre { white-space: normal; }
Basile Beldame
  • 410
  • 1
  • 4
  • 15
0

Not sure if there is a better answer elsewhere but I did come up a very brittle/hacky solution to this problem. It uses some magic numbers in my example but I think it could be the starting point of a somewhat better answer in the future.

This solution boils down to using position: absolute; without any values for top, right, bottom, or left on the item you want to be overflow: visible and setting it's parent to overflow: scroll;.

The default behaviour of an absolutely positioned element without any absolute values is in between the static and absolute positioned world I want it to be in, sort of.

CODEPEN

Codepen

HTML

<div class="wrapper">
  <div class="inner-wrapper">
    <div class="item">Item 1</div>
    <div class="item">Item 2</div>
    <div class="item">Item 3</div>
    <div class="item">Item 4</div>
    <div class="item" id="dropdown">
      Hover me
      <div class="menu">Menu</div>
    </div>
  </div>
</div>

CSS

.wrapper {
  background: blue;
  height: 64px;
  width: 250px;
  padding: 2px;
}

.inner-wrapper {
  overflow-x: scroll;
  display: flex;
  height: 100%;
}

.item {
  background: white;
  margin-right: 2px;
  width: 60px;
  height: 100%;
  flex-shrink: 0;
}

#dropdown .menu {
  background: pink;
  height: 0px;
  position: absolute;
  display: none;
}

#dropdown:hover .menu {
  height: 100px;
  z-index: 1;
  display: block;
  margin-left: -58px;
}

I posted a small video clip of the problem I was trying to solve for on Twitter

Peter W
  • 1,324
  • 1
  • 14
  • 23
-2

Try changing overflow-y: hidden