1
votes

I want to move pseudo-element when we hover on the current div. Here pink color div I want to move vertically in front of the currently hovered div. Can anyone suggest to me how can I achieve this output

enter image description here

$(document).ready(function() {
  $(".timeline-entry").hover(function(e) {
    e.preventDefault();
    $('.timeline-entry.current').removeClass('current');
    $(this).addClass('current');
  });
});
.timeline {
  position: relative;
  display: flex;
  flex-direction: column;
}

article {
  width: 100px;
  height: 50px;
  background: red;
}

.timeline-entry.right-aligned {
  align-self: flex-end;
  background: blue;
}

.timeline-entry.left-aligned {
  float: left;
}

.timeline:after {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  width: 20px;
  height: 50px;
  background: pink;
}


/* .timeline-entry:hover .timeline:nth-child(1) .timeline:after {
  top: 100px;
} */

.timeline-entry.current {
  background: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<div class="timeline">
  <article class="timeline-entry right-aligned"></article>
  <article class="timeline-entry left-aligned"></article>
  <article class="timeline-entry right-aligned"></article>
  <article class="timeline-entry left-aligned"></article>
</div>
1
Is it necessary to move that pink element? Because if not, then it can be done easily with only CSS for every hovered div. - Gil
@Gil Yes I want to move :after pink element top to bottom - Husna
Couldn't you do this by using :after or :before on the children instead? It's tricky to move it on the parent based on child position. Only way I can think of is write into a style tag with js. I just did some attempts using css attr() function but it has limited support for properties other than content - charlietfl
Or make it an actual dom element instead of using :after? You could even animate a real element - charlietfl
@Husna Here's the problem, moving the pseudo element will require calculating its absolute position in relation to the hovered element, and it will break the moment the page size changes, so this will require adding a resize listener. A more reliable solution is to set it as a non-pseudo element and add it as a child to the hovered element, but if the end result is showing the same element on hover, setting the :after selector will do it nicely. - Gil

1 Answers

0
votes

This solution is on the assumption that you don't need the exact same element to move and only interested in showing it on hover. I'm still not sure what you actually want. This is done with pure CSS without the need for any JS code.

.timeline {
  position: relative;
  display: flex;
  flex-direction: column;
}
article {
  width: 100px;
  height: 50px;
  background: red;
  position: relative;
}
.timeline-entry.right-aligned {
  align-self: flex-end;
  background: blue;
}
.timeline-entry.left-aligned {
  float: left;
}
.timeline-entry:hover {
  background: yellow;
}
.timeline-entry:hover:after {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  width: 20px;
  height: 100%;
  background: pink;
}
<div class="timeline">
  <article class="timeline-entry right-aligned"></article>
  <article class="timeline-entry left-aligned"></article>
  <article class="timeline-entry right-aligned"></article>
  <article class="timeline-entry left-aligned"></article>
</div>

I also changed the pseudo-element height to 100% since it's now contained by the article element.

UPDATE

This is another answer, followed by the question update.

article {
  height: 50px;
  position: relative;
}
article div {
  width: 100px;
  height: 100%;
}
.timeline-entry.right-aligned div {
  float: right;
  background: blue;
}
.timeline-entry.left-aligned div {
  float: left;
  background: red;
}
.timeline-entry div:hover {
  background: yellow;
}
.timeline-entry div:hover::after {
  content: '';
  position: absolute;
  top: 0;
  left: calc(50% - 10px);
  width: 20px;
  height: 100%;
  background: pink;
}
<div class="timeline">
  <article class="timeline-entry right-aligned"><div></div></article>
  <article class="timeline-entry left-aligned"><div></div></article>
  <article class="timeline-entry right-aligned"><div></div></article>
  <article class="timeline-entry left-aligned"><div></div></article>
</div>

There are other ways to reach this result. I've kept the CSS only approach.