Noah Potter
Noah Potter

Reputation: 63

Getting CSS :hover on overlapping siblings

This is easiest to understand when running the code below. I'm looking to trigger the hover state on both a column and the middle row when hovering over the red bar.

I'd like to keep the columns based on flex and have the bar absolutely positioned over them.

Is this possible?

EDIT:

I'd like just the column that the mouse is hovering over to turn blue. Sorry for the ambiguity. Snippet updated with desired result.

The columns are divided by a white line. Hover over a grey area to see the column highlighted.

Thanks.

.root {
  width: 100px;
  height: 100px;
  background: grey;
  position: relative;
  display: flex;
}

.column {
  display: flex;
  flex: 1 1 auto;
  border-right: 1px solid white;
}

.column:hover {
  background: blue;
}

.bar {
  position: absolute;
  left: 0;
  right: 0;
  top: 33px;
  bottom: 33px;
  background: red;
}

.bar:hover {
  background: green;
}

.green {
  background: green;
}

.blue {
  background: blue;
}
Hover over the middle of the square. I want the middle column to turn blue and the bar to turn green.
Right now, only the bar turns green.

<div class='root'>
  <div class='column'>
  </div>
  <div class='column'>
  </div>
  <div class='column'>
  </div>
  <div class='bar'>
  </div>
</div>

Desired result: 

<div class='root'>
  <div class='column'>
  </div>
  <div class='column blue'>
  </div>
  <div class='column'>
  </div>
  <div class='bar green'>
  </div>
</div>

Final Edit:

I'm providing a fully fleshed out version of what my use case is. I don't think CSS will be able to solve this, but I've accepted an answer that works for my original question.

function enterColumn() {
  document.getElementById('column-status').innerHTML = 'In column'
}

function leaveColumn() {
  document.getElementById('column-status').innerHTML = 'Out of column'
}

function enterBar() {
  document.getElementById('bar-status').innerHTML = 'In bar'
}

function leaveBar() {
  document.getElementById('bar-status').innerHTML = 'Out of bar'
}
.root {
  width: 100px;
  height: 100px;
  background: grey;
  position: relative;
  display: flex;
}

.column {
  display: flex;
  flex: 1 1 auto;
  border-right: 1px solid white;
}

.column:hover {
  background: blue;
}

.bar-container {
  position: absolute;
  left: 0;
  right: 0;
  top: 33px;
  bottom: 33px;
}

.bar {
  position: absolute;
  top: 0;
  bottom: 0;
  background: red;
}

.bar:hover {
  background: green;
}

.green {
  background: green;
}

.blue {
  background: blue;
}
Hovering over a column or bar should be independent. Right now you can never have the 'In column' and 'In bar' status at the same time :(
<br />
It should scale to support any number of columns and any number of bars (where bars can be absolutely positioned anywhere along the x-axis)
<br />
Javascript events should be called on mouse events for both columns and bars.

<div class='root'>
  <div class='column' onmouseenter='enterColumn();' onmouseleave='leaveColumn()'>
  </div>
  <div class='column' onmouseenter='enterColumn();' onmouseleave='leaveColumn()'>
  </div>
  <div class='column' onmouseenter='enterColumn();' onmouseleave='leaveColumn()'>
  </div>
  <div class='bar-container'>
    <div class='bar' style='left: 5px; right: 40px' onmouseenter='enterBar();' onmouseleave='leaveBar()'>
    </div>
    <div class='bar' style='left: 65px; right: 5px' onmouseenter='enterBar();' onmouseleave='leaveBar()'>
    </div>
  </div>
</div>

<div id='column-status'>
  Out of column
</div>
<div id='bar-status'>
  Out of bar
</div>

Upvotes: 5

Views: 698

Answers (3)

Etienne Martin
Etienne Martin

Reputation: 11609

There you go, after 2 hours of trial and error I finally came up with this little hack.

.root {
  width: 100px;
  height: 100px;
  background: grey;
  position: relative;
  display: flex;
}

.column {
  display: flex;
  flex: 1 1 auto;
  border-right: solid #fff 1px;
}

.column:hover {
  background: blue;
}

.column .toggle{
  margin-top:33px;
  height: 33px;
  width: 100%;
}

.column .toggle:before{
  content: "";
  position: absolute;
  width: 34px;
  height: 33px;
}

.column .toggle:hover:after{
  content: "";
  position: absolute;
  z-index: 10;
  left: 0;
  right: 0;
  top: 33px;
  bottom: 33px;
  background: green;
  pointer-events:none;
}

.bar {
  position: absolute;
  z-index: 1;
  left: 0;
  right: 0;
  top: 33px;
  bottom: 33px;
  background: red;
  pointer-events:none;
}
<div class='root'>
  <div class='column'><div class='toggle'></div></div>
  <div class='column'><div class='toggle'></div></div>
  <div class='column'><div class='toggle'></div></div>
  <div class='bar'></div>
</div>

Now if you need to bind some javascript events to the .bar element, attach them to .toggle instead.

Upvotes: 2

user4447799
user4447799

Reputation:

If rearrangement of divs is allowed, you can position the .bar just before the middle .column and use adjacent sibling selector.

.bar:hover + .column {
     background: blue;
}

.root {
  width: 100px;
  height: 100px;
  background: grey;
  position: relative;
  display: flex;
}

.column {
  display: flex;
  flex: 1 1 auto;
  border-right: 1px solid white;
}

.column:hover {
  background: blue;
}

.bar {
  position: absolute;
  left: 0;
  right: 0;
  top: 33px;
  bottom: 33px;
  background: red;
}

.bar:hover {
  background: green;
}

.bar:hover + .column {
  background: blue;
}

.green {
  background: green;
}

.blue {
  background: blue;
}
<div class='root'>
  <div class='column'>
  </div>
  <div class='bar'>
  </div>
  <div class='column'>
  </div>
  <div class='column'>
  </div>
</div>

Upvotes: 1

Zahid Saeed
Zahid Saeed

Reputation: 1181

If I understand what you mean, you mean that if you hover over any element the .column should turn blue and .bar should turn green. If that's the case then actually its pretty simple. Just place your hover event on .root element instead like so:

.root {
  width: 100px;
  height: 100px;
  background: grey;
  position: relative;
  display: flex;
}

.column {
  display: flex;
  flex: 1 1 auto;
  border-right: 1px solid white;
}

.bar {
  position: absolute;
  left: 0;
  right: 0;
  top: 33px;
  bottom: 33px;
  background: red;
}

.root:hover .bar {
  background: green;
}

.root:hover .column {
  background: blue;
}
<div class='root'>
  <div class='column'>
  </div>
  <div class='column'>
  </div>
  <div class='column'>
  </div>
  <div class='bar'>
  </div>
</div>

If that' not the case and you want the color of the .column to change when you hover over the .bar then check out the snippet below. Note that I've a changed the HTML markup a bit. Since .bar has position: absolute so it won't affect at all where you place it inside the .root element.

.root {
  width: 100px;
  height: 100px;
  background: grey;
  position: relative;
  display: flex;
}

.column {
  display: flex;
  flex: 1 1 auto;
  border-right: 1px solid white;
}

.bar {
  position: absolute;
  left: 0;
  right: 0;
  top: 33px;
  bottom: 33px;
  background: red;
}

.bar:hover {
  background: green;
}

.bar:hover ~ .column {
  background: blue;
}
<div class='root'>
  <div class='bar'>
  </div>
  <div class='column'>
  </div>
  <div class='column'>
  </div>
  <div class='column'>
  </div>
</div>

Let me know if that helps you :-)

Upvotes: 0

Related Questions