CLL
CLL

Reputation: 1342

How can I prevent an absolutely positioned element from breaking within CSS columns?

I have a 2 column layout using HTML and CSS. Within these columns, I have a selectmenu that will show when one of these list items are clicked. I need to position this selectmenu relative to the clicked item and not affect the layout of the elements around it, like a traditional select option menu. However, I cannot use traditional selects, as this is an autosuggest input/menu. So, I am using an absolutely positioned item for the menu container within its relatively positioned parent.

What I want: list with absolutely positioned child in columned layout

My problem is the absolutely positioned item is breaking as if it were part of the columns. This goes against everything I understand about position: absolute, but it appears it is within spec. What is more frustrating is that the browser shows the absolutely positioned item as I intend it (as long as I don’t set position: relative on the parent), but I need to set position: relative on the parent, or the selectmenu (as an absolutely positioned item) won’t always show adjoining its corresponding element.

What I get: enter image description here

I have also tried a column-like layout using using flexbox, but with this, the items are shown left to right, when I need them to be shown top to bottom, in order, as in a traditional columned layout. I could use flexbox with flex-flow: column wrap, but that would require me to know/set the height of the container element, which I cannot do. CSS columns wrap the list nicely without having to set a height.

I think the easiest solutions would be to somehow fake absolute positioning or to get flexbox to show the items in order (top to bottom) without explicitly setting a height on the container. Both of which I tried with no satisfactory results. I am open to using a JavaScript solution, but am trying my best to avoid it and solve this with CSS only.

.columns-two {
  column-count: 2;
  column-width: 300px;
  -moz-column-count: 2;
  -moz-column-width: 300px;
}
.parent {
  -webkit-column-break-inside: avoid;
  page-break-inside: avoid;
  break-inside: avoid;
  position: relative;
}
.highlight {
  background-color: #FFF8DC;
}
.absolute-element {
  width: 200px;
  position: absolute;
  background: #ffffff;
  border: 1px solid #cccccc;
  padding: 15px;
  -webkit-column-break-inside: avoid;
  page-break-inside: avoid;
  break-inside: avoid;
}
<ul class="columns-two">
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li class="parent highlight">item that shows selectmenu
    <div class="absolute-element">This is an absolute element. This is an absolute element. This is an absolute element. This is an absolute element. This is an absolute element. This is an absolute element. This is an absolute element. This is an absolute element.This is an absolute
      element. This is an absolute element. This is an absolute element. This is an absolute element.</div>
  </li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
  <li>item</li>
</ul>

Here is a codepen with an example showing my problem. Remove the parent class from the HTML to see the absolutely positioned item as intended (note that this will cause the positioning to sometimes be incorrect).

Upvotes: 13

Views: 3280

Answers (4)

CLL
CLL

Reputation: 1342

I've found that using transform: translate3d(0,0,0); on the absolutely positioned element will prevent its column break.

Upvotes: 3

Ramzi Dreessen
Ramzi Dreessen

Reputation: 102

Use backface-visibility: hidden on the child element.

Upvotes: 5

user7398334
user7398334

Reputation: 1

Just set position:relative to ul, and position submenu if you need with property margin.

Upvotes: -1

Toby
Toby

Reputation: 13365

Are you able to set the <li> to position: relative; with the select menu positioned absolutely inside the <li>? AFAIK this is the standard way of achieving this effect.

Then:

.selectMenu {
    position: absolute;
    top: /* height of li element */;
    left: 0;
}

Upvotes: 0

Related Questions