如何用CSS实现剧透报价?

时间:2015-12-14 03:06:24

标签: html css hover

我有blockquote这样:

<blockquote class="spoiler">Soopah sekkrit!</blockquote>

我想隐藏它,只有当用户将鼠标悬停在它上面时才显示它。我现在正在使用JS:

blockquote.addEventListener('mouseover', function() {
    this.style.height = this.offsetHeight + 'px';
    this.dataset.contents = this.innerHTML;
    this.innerHTML = '';
});
blockquote.addEventListener('mouseout', function() {
    this.style.height = '';
    this.innerHTML = this.dataset.contents;
});

使用CSS有没有更好的方法呢?

它必须保持其background-color,大小和内容的自定义颜色。如果可能的话,我也想制作它的动画,以便内容逐渐淡出。

3 个答案:

答案 0 :(得分:14)

这与我在SOUP中使用的内容非常相似:

.spoiler, .spoiler > * { transition: color 0.5s, opacity 0.5s }
.spoiler:not(:hover) { color: transparent }
.spoiler:not(:hover) > * { opacity: 0 }
/* fix weird transitions on Chrome: */
blockquote, blockquote > *:not(a) { color: black }

.spoiler, .spoiler > * { transition: color 0.5s, opacity 0.5s }
.spoiler:not(:hover) { color: transparent }
.spoiler:not(:hover) > * { opacity: 0 }
/* fix weird transitions on Chrome: */
blockquote, blockquote > *:not(a) { color: black }

/* some basic bg styles for demonstration purposes */
blockquote { background: #fed; margin: 1em 0; padding: 8px; border-left: 2px solid #cba }
code { background: #ccc; padding: 2px }
img { vertical-align: middle }
<blockquote class="spoiler">
  Soopah sekkrit text with <code>code</code> and <a href="#">links</a> and <img src="//sstatic.net/stackexchange/img/logos/so/so-logo-med.png" width="100" /> images!
  <p>You can also have paragraphs in here.</p>
  <ul><li>And lists too!</li></ul>
  <blockquote class="spoiler">Even nested spoilers work!</blockquote>
</blockquote>

这比your own solution稍微简单,适用于任意内容,包括图像甚至嵌套剧透! (参见上面的演示片段。)

唉,如果扰流板的任何子元素都有color: inherit,这种方法似乎会受到Chrome上奇怪的过渡效果的影响。 (基本上,正在发生的是这些元素将两者将其文本颜色设置为透明,并将其不透明度设置为0.因为不透明度会成倍增加,因此组合过渡将显得更慢 - 在淡入淡出的中途 - 在,当元素本身的不透明度为50%时,其中的文本为50%×50%= 25%不透明度。)我在上面的示例中添加了一个额外的CSS规则来修复这,但它确实使事情变得有点复杂。

在SOUP中实际做的事情略有不同。我将每个剧透的内容包装在一个额外的内部<div>中,这让我可以进一步简化CSS:

.spoiler > div { opacity: 0; transition: opacity 0.5s }
.spoiler:hover > div { opacity: 1 }

.spoiler > div { opacity: 0; transition: opacity 0.5s }
.spoiler:hover > div { opacity: 1 }

/* some basic bg styles for demonstration purposes */
blockquote { background: #fed; margin: 1em 0; padding: 8px; border-left: 2px solid #cba }
code { background: #ccc; padding: 2px }
img { vertical-align: middle }
<blockquote class="spoiler"><div>
  Soopah sekkrit text with <code>code</code> and <a href="#">links</a> and <img src="//sstatic.net/stackexchange/img/logos/so/so-logo-med.png" width="100" /> images!
  <p>You can also have paragraphs in here.</p>
  <ul><li>And lists too!</li></ul>
  <blockquote class="spoiler"><div>Even nested spoilers work!</div></blockquote>
<div></blockquote>

此方法的主要优点是简单性和健壮性:我不必使用:not()选择器,提高与旧浏览器的兼容性,transition样式不能与其他转换冲突在剧透内部的内部上定义。此方法也不会受到上述Chrome上的颜色过渡怪异的影响,因为它只使用不透明度过渡。

总的来说,这是我推荐的方法。当然,缺点是您需要在HTML中包含额外的<div>

Ps。请考虑提供一些方法使剧透图永久可见,尤其是对于可能发现很难将光标“悬停”在元素上的触摸屏用户。一个简单的解决方案是使用JavaScript单击事件处理程序来切换spoiler类,例如像这样(使用jQuery):

$('.spoiler').on( 'click', function (e) {
  $(this).toggleClass('spoiler');
  e.stopPropagation();
} );

$('.spoiler').on( 'click', function (e) {
  $(this).toggleClass('spoiler');
  e.stopPropagation();
} );
.spoiler > div { opacity: 0; transition: opacity 0.5s }
.spoiler:hover > div { opacity: 1 }

/* some basic bg styles for demonstration purposes */
blockquote { background: #fed; margin: 1em 0; padding: 8px; border-left: 2px solid #cba }
code { background: #ccc; padding: 2px }
img { vertical-align: middle }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<blockquote class="spoiler"><div>
  Soopah sekkrit text with <code>code</code> and <a href="#">links</a> and <img src="//sstatic.net/stackexchange/img/logos/so/so-logo-med.png" width="100" /> images!
  <p>You can also have paragraphs in here.</p>
  <ul><li>And lists too!</li></ul>
  <blockquote class="spoiler"><div>Even <a href="//example.com">nested</a> spoilers work!</div></blockquote>
<div></blockquote>

或者,如果您更喜欢使用委托事件处理(这样您每次通过Ajax加载包含剧透的新内容时都不必继续添加新的点击处理程序):

$(document).on( 'click', '.spoiler, .spoiler-off', function (e) {
  $(this).toggleClass('spoiler').toggleClass('spoiler-off');
  e.stopPropagation();
} );

$(document).on( 'click', '.spoiler, .spoiler-off', function (e) {
  $(this).toggleClass('spoiler').toggleClass('spoiler-off');
  e.stopPropagation();
} );
.spoiler > div { opacity: 0; transition: opacity 0.5s }
.spoiler:hover > div { opacity: 1 }

/* some basic bg styles for demonstration purposes */
blockquote { background: #fed; margin: 1em 0; padding: 8px; border-left: 2px solid #cba }
code { background: #ccc; padding: 2px }
img { vertical-align: middle }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<blockquote class="spoiler"><div>
  Soopah sekkrit text with <code>code</code> and <a href="#">links</a> and <img src="//sstatic.net/stackexchange/img/logos/so/so-logo-med.png" width="100" /> images!
  <p>You can also have paragraphs in here.</p>
  <ul><li>And lists too!</li></ul>
  <blockquote class="spoiler"><div>Even <a href="//example.com">nested</a> spoilers work!</div></blockquote>
<div></blockquote>

(这些应该适用于上面显示的任何CSS变体。)

答案 1 :(得分:11)

是的,这可以通过CSS实现。基本上,您希望使所有内容都不可见。在CSS中,这意味着透明。

首先使用hover pseudo-class中的not pseudo-class

.spoiler:not(:hover)

但我们还需要选择悬停扰流板的所有子元素,设置它们的颜色和背景:

.spoiler:not(:hover) *

我们将颜色和背景(仅适用于子元素)设置为transparent,以使其对用户不可见。一起来:

.spoiler:not(:hover), .spoiler:not(:hover) * { color: transparent }
.spoiler:not(:hover) * { background: transparent }

code { padding: 2px; background: #bbb }
a { color: #00f }
Hover: <blockquote class="spoiler">Some stuff <a>and a colored link</a> <code>and some code!</code></blockquote>

我们还可以添加transition以使其更顺畅:

.spoiler { transition: color 0.5s } /* we have to put this outside the :hover to make it work fading both in and out */
.spoiler:not(:hover), .spoiler:not(:hover) * { color: transparent }
.spoiler * { transition: color 0.5s, background 0.5s }
.spoiler:not(:hover) * { background: transparent }

code { padding: 2px; background: #bbb; color: #000 } /* add color to prevent double transition */
a { color: #00f }
Hover: <blockquote class="spoiler">Some stuff <a>and a colored link</a> <code>and some code!</code></blockquote>

为了让用户明白blockquote是可以缓存的,你可以添加一些::after pseudo-element的文本,以便在没有悬停块引用时显示:

.spoiler { transition: color 0.5s; position: relative } /* relative position for positioning the pseudo-element */
.spoiler:not(:hover), .spoiler:not(:hover) * { color: transparent }
.spoiler * { transition: color 0.5s, background 0.5s }
.spoiler:not(:hover) * { background: transparent }
.spoiler::after {
    content: 'hover to view spoiler';
    position: absolute;
    top: 0; left: 0;
    color: transparent;
}
.spoiler:not(:hover)::after {
    color: #666;
    transition: color 0.3s 0.3s; /* delayed transition to keep the text from overlapping */
}

code { padding: 2px; background: #bbb; color: #000 }
a { color: #00f }
<blockquote class="spoiler">
    Some stuff <a>and a colored link</a> <code>and some code!</code>
    <blockquote class="spoiler">Nesting bonus!</blockquote>
</blockquote>

对于像图像,svgs(内联SVG可以非常精细控制),画布和所有那些花哨的东西,而不是color,你必须使用opacity。我们可以通过添加以下内容使其成功:

.spoiler img { transition: opacity 0.5s, background 0.5s }
.spoiler:not(:hover) img { opacity: 0 }

答案 2 :(得分:0)

这是一种效果很好,看起来不错并且过渡非常干净的策略

CompletableFuture

如果您使用MainThread为父块设置样式而不设置鼠标悬停,则无法添加任何样式来说明用户应将鼠标悬停在页面的哪一部分。

相反,如果我们添加一个.spoiler { position: relative; display: inline-block; cursor: help; } .spoiler::before { content: 'psst\02026'; /* &hellip; */ position: absolute; left: -2px; top: -2px; right: -2px; bottom: -2px; border-radius: 1px; font-size: .9rem; color: #e6578c; background: #ffe5e5; display: flex; align-items: center; justify-content: center; text-align: center; opacity: 1; transition: opacity 0.7s ease, transform 0.3s ease; /* hide faster than reveal */ } .spoiler:hover::before { opacity: 0; transform: translateY(-50%)rotateX(80deg); transition: opacity 1.0s ease, transform 0.5s ease; /* slower reveal */ } 元素来掩盖子内容,那么我们可以在悬停时淡出它,并仍然提供视觉指示。

堆栈摘要中的演示

Spoiler Demo

opacity: 0
::before