mezod mezod - 5 months ago 8
CSS Question

Selecting only immediately hovered element in CSS for nested elements

I have a collection of nested comments. My goal is to display a 'reply' option when hovering each comment separately. This means that I don't want the 'reply' option to show up for parent/sibling/children of the comment I am hovering.

The only similar question I have found is: Can I control CSS selection for :hover on nested elements? I am not even sure his needs are the same, and additionally the fiddles don't seem to work.

I have prepared a fiddle so you better see what I mean: https://jsfiddle.net/Ls50sLpc/1/



.comment {
padding: 10px;
border: 1px solid black;
margin-top: 10px;
}
.text {} .comment:hover > .reply {
display: inline-block;
}
.reply {
display: none;
}
.children-comments {
margin-left: 50px;
margin-top: 10px;
}

<div class="comment">
<a class="text">wohoo</a>
<a class="reply">reply</a>
<div class="children-comments">
<div class="comment">
<a class="text">wohoo</a>
<a class="reply">reply</a>
<div class="children-comments">

</div>
</div>
<div class="comment">
<a class="text">wohoo</a>
<a class="reply">reply</a>
<div class="children-comments">
<div class="comment">
<a class="text">wohoo</a>
<a class="reply">reply</a>
<div class="children-comments">
<div class="comment">
<a class="text">wohoo</a>
<a class="reply">reply</a>
<div class="children-comments">

</div>
</div>
</div>
</div>
</div>
</div>
<div class="comment">
<a class="text">wohoo</a>
<a class="reply">reply</a>
<div class="children-comments">

</div>
</div>
</div>
</div>





Notice that using > in the selector does work to ignore the sibling elements but it still selects the parent elements. In other words, no matter which comment you hover, the parent of them all will always show the 'reply' option.

Can this be done with CSS only at all? I'm open to js solutions but I'd be more than happy if there was a CSS only solution. Thank you!

Answer

Your best option would be to change the markup a little bit and add a wrapper:

<div class="comment">
  <div class="content">   <!-- Here -->
    <a class="text">wohoo</a>
    <a class="reply">reply</a>
  </div>

By adding a div wrapper for the content, you can target comments individually using .content:hover > .reply

Example:

.comment {
  padding: 10px;
  border: 1px solid black;
  margin-top: 10px;
}

.text {}

.content:hover > .reply {
  display: inline-block;
}

.reply {
  display: none;
}

.children-comments {
  margin-left: 50px;
  margin-top: 10px;
}
<div class="comment">
  <div class="content">
    <a class="text">wohoo</a>
    <a class="reply">reply</a>
  </div>
  <div class="children-comments">
    <div class="comment">
      <div class="content">
        <a class="text">wohoo</a>
        <a class="reply">reply</a>
      </div>
      <div class="children-comments">
        <div class="comment">
          <div class="content">
            <a class="text">wohoo</a>
            <a class="reply">reply</a>
          </div>
        </div>
        <div class="children-comments">
          <div class="comment">
            <div class="content">
              <a class="text">wohoo</a>
              <a class="reply">reply</a>
            </div>
            <div class="children-comments">
              <div class="comment">
                <div class="content">
                  <a class="text">wohoo</a>
                  <a class="reply">reply</a>
                </div>
                <div class="children-comments">

                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      <div class="comment">
        <div class="content">

          <a class="text">wohoo</a>
          <a class="reply">reply</a>
          <div class="children-comments">
          </div>
        </div>
      </div>
    </div>
  </div>

The content wrapper would expand to the area of the actual content of the comment (which makes the most sense).

However, you could also make the wrapper expand to the entire comment block as well (more than just the comment's content) by using positioning styles. For example:

/* OPTIONAL - These style changes make the content
 * wrapper cover the entire comment block.
 */
.comment {
  padding: 10px;
  border: 1px solid black;
  margin-top: 10px;
  position:relative;
}

.comment .content {
  width:100%;
  height:100%;
  position:absolute;
  top:0;
  left:0;
}

It just depends on your desired behavior.

(jsFiddle example)