忽略伪元素:before或:after的边距

6
我正在尝试为给定的一组通用HTML元素标记边框(它们的CSS不在我的控制范围内),以便边框可见,并且在悬停时突出显示。我目前使用伪元素:before和:after来实现这一点,但是我在处理边距时遇到了问题。我需要使用CSS而不是JS来解决。期望的行为是仅在任何两个元素之间有单个线条,但由于边距,在段落“Some content”和标题“World”之间重复了边框。我能够将标记类应用于包装div或直接应用于类元素,如下面的片段所示,两者对我来说都可以。

.mark-borders:before,
.mark-borders:after
{
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  display: block;
  height: 1px;
  border-bottom: dashed 1px #ccc;
}

.mark-borders:hover:before,
.mark-borders:hover:after
{
  border-bottom: solid 1px red;
  z-index: 1;
}
<div class="mark-borders">
  <h1>
    Hello
  </h1>
</div>
<div class="mark-borders">
  <p>
   Some content
  </p>
</div>
<div class="mark-borders">
  <h1>
    World
  </h1>
</div>
<br />
<hr />
<div class="mark-borders">
  <h1>
    Hello
  </h1>
</div>
<p class="mark-borders">
 Some content
</p>
<h1 class="mark-borders">
  World
</h1>

有没有办法在不使用JS放置边框线的情况下“合并”两个边框,同时保留悬停高亮效果?
我尝试对所有元素使用:after,只对第一个元素使用:before,但在这种情况下,我要么失去了顶部边框的悬停效果,要么显示在错误的位置(与原始边框相同问题)。
更新:
我能够使用以下概念组合几乎可行的解决方案:
每个元素显示其:before边框
最后一个元素还显示其:after边框
悬停时,当前元素和其下一个兄弟的:before边框都会被激活
但是...即使它比原始版本更好用,“margin”区域也无法响应:hover,请问有什么解决方法?
更新后的代码:

.mark-borders:before,
.mark-borders:last-child:after
{
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  display: block;
  height: 1px;
  border-bottom: dashed 1px #ccc;
}

.mark-borders:hover:before,
.mark-borders:hover:last-child:after,
.mark-borders:hover + *:before
{
  border-bottom: solid 1px red;
  z-index: 1;
}
<div>
  <div class="mark-borders">
    <h1>
      Hello
    </h1>
  </div>
  <div class="mark-borders">
    <p>
      Some content
    </p>
  </div>
  <div class="mark-borders">
    <h1>
      World
    </h1>
  </div>
</div>


你想为每个 div 使用 1 个边框,对吧? - claudios
是的,我想在每个div之间有一个显示的边框,以及在第一个和最后一个之前都需要边框,但是我需要在悬停时同时突出显示前后边框。我只能想到一种半成品解决方案,稍后我会更新问题并展示我的进展。 - martinh_kentico
啊,我明白了。只需要添加.mark-borders{overflow:hidden}并相应地重新定位您的before和after即可。 - Ron.Basco
2个回答

3
我已经编辑过你的代码,并得出了以下结果:https://jsfiddle.net/7g31c5rp/4/
.mark-borders:nth-of-type(2):after,
  p.mark-borders:after{
  display: none;
}
.mark-borders:hover + .mark-borders:before{
   border-bottom: solid 1px red;
   z-index: 1;
}

当鼠标悬停时,移除some-content后面的内容并选中WORLD之前的内容。


谢谢,与此同时我已经更新了我的问题,加入了类似的概念。我也不能选择性地仅向某些元素添加类,我需要将相同的类应用于单个父节点的所有子节点。 - martinh_kentico
我也不能依赖于特定的元素类型,它需要在具有特定额外类(在我的情况下为mark-borders)的一般平面元素列表上工作。您的解决方案与我已经拥有的解决方案具有相同的行为。您有任何想法如何使边距区域响应:hover,无论是在我的解决方案还是在您的解决方案中? - martinh_kentico
我认为你应该使用JavaScript。 - Ron.Basco
1
啊,我明白了。只需添加这个.mark-borders{overflow:hidden},然后相应地重新定位你的 before 和 after 即可。 - Ron.Basco
我明白了,所以在我看来,overflow:hidden会将margin的行为变得更像padding的行为,但在这种情况下,我从两侧应用了margin(内容扩展超出了应有的范围)。但很有趣的是知道这样的事情是可能的,谢谢!你提到的重新定位前后是指通过JavaScript实现,对吗? - martinh_kentico

1

只需使用兄弟选择器在:before中添加边框,然后给:last-child添加:after边框。

.mark-borders:before,
.mark-borders + .mark-borders:before,
.mark-borders:last-child:after
{
  content: '';
  display: block;
  position: absolute;
  height: 0;
  width: 100%;
  margin-top: -1px;
  border-bottom: dashed 1px #ccc;
}

.mark-borders:hover:before,
.mark-borders:hover + .mark-borders:before,
.mark-borders:last-child:hover:after
{
  border-bottom: solid 1px red;
  z-index: 1;
}
<div>
  <div class="mark-borders">
    <h1>
      Hello
    </h1>
  </div>
  <div class="mark-borders">
    <p>
      Some content
    </p>
  </div>
  <div class="mark-borders">
    <h1>
      World
    </h1>
  </div>
</div>


乍一看似乎很有前途,但我不被允许影响原始元素的定位,只能标记边框,这就是为什么我在示例中使用了position: absolute。您的解决方案增加了额外(不需要的)空间。有没有办法在不改变原始底层设计的情况下完成这项任务? - martinh_kentico
1
@martinh_kentico 看一下我的更新片段。我猜应该就这样了? - tmslnz
这正是我在更新的问题中已经有的,但是边距区域没有响应:hover,有什么想法可以修复吗? - martinh_kentico
我开始认为在放松一些限制之前可能不可能实现。您能否提供更多信息,为什么您只能添加一个类等。 - tmslnz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接