如何使用内容元素的HTML内容创建纯CSS工具提示

时间:2016-11-10 15:17:53

标签: php html css css3 tooltip

  

TL; DR - 请参阅亚当的回答(已接受)或更新#5   当前解决方案的问题。我的问题显示了我的旅程   以相当长但解释的方式获得该解决方案,   描述陷阱和限制。

我正在创建一个模块,为文本中使用的相应单词添加词汇表术语描述。使用纯文本描述一切正常。例如,如果有onomasticon(同义词的另一个词)的描述,则为以下HTML

<p>An onomasticon is not a dinosaur.</p>

转换为

&#13;
&#13;
<p>An <dfn title="Another word for thesaurus">onomasticon</dfn> is not a dinosaur.</p>
&#13;
&#13;
&#13;

由于内容(文章文本和词汇表术语描述)都来自允许用户使用HTML的CMS,因此术语的描述可能包含HTML,例如: Another word for <strong>thesaurus</strong>。使用上述技术,这开始变得混乱:

&#13;
&#13;
<p>An <dfn title="Another word for <strong>thesaurus</strong>">onomasticon</dfn> is not a dinosaur.</p>
&#13;
&#13;
&#13;

这是默认情况下,因为标记属性本身可能不包含标记。可以通过在dfn标记内添加其他元素并添加一些CSS来最初隐藏元素来绕过此限制:

&#13;
&#13;
dfn span {
  display: none;
}
dfn:hover span {
  display: block;
  position: absolute;
  top: 2.2em;
  background: #ccc;
}
&#13;
<p>An <dfn><span>Another word for <strong>thesaurus</strong></span>onomasticon</dfn> is not a dinosaur.</p>
&#13;
&#13;
&#13;

但现在来了,我没有克服。像<strong>这样的HTML标记是内联元素,不会造成任何问题。但是,如果术语的描述包含一个块元素,则会失败,例如如果描述本身包含在<p>标记中:

&#13;
&#13;
dfn span {
  display: none;
}
dfn:hover span {
  display: block;
  position: absolute;
  top: 2.2em;
  background: #ccc;
}
&#13;
<p>An <dfn><span><p>Another word for <strong>thesaurus</strong></p></span>onomasticon</dfn> is not a dinosaur.</p>
&#13;
&#13;
&#13;

这里发生了什么?好吧,由于大多数内联元素中不允许使用块元素,因此外部内联元素将被终止,内部块元素将被放置在其后。因此,CSS选择器不再起作用,而且你最终会有额外的换行符。当然,有人可能会考虑添加类似dfn span p { display: inline-block; }的内容,但这也不起作用(inline也不起作用),它是无效的HTML5。

虽然在语义上不正确,但我尝试将<dfn>转换为<div class="dfn">而将内部<span>转换为<div>,因为dfn,abbr和cite元素可能只包含措辞上下文(就像跨度)。由于在<div>内不允许<p>,再次失败,再次添加了不需要的换行符:

&#13;
&#13;
.dfn > div {
  display: none;
}
.dfn:hover div {
  display: inline-block;
  position: absolute;
  top: 2.2em;
  background: #ccc;
}
&#13;
<p>An <div class="dfn"><div><p>Another word for <strong>thesaurus</strong></p></div>onomasticon</div> is not a dinosaur.</p>
&#13;
&#13;
&#13;

这是我迄今为止的旅程总结,试图达到将包含HTML的工具提示添加到内联元素的圣杯 - 例如<dfn><abbr>或{{1只使用CSS。

在我现在研究基于javascript的解决方案之前,我的问题是我是否错过了满足下列要求的选项?

  • 仅限CSS
  • 工具提示必须添加到段落中的<cite><dfn><abbr>
  • 工具提示内容可能包含以下HTML标记:div,p,h2,img,figure,ul,ol,li

更新1:由于我编写了模块(PHP),我当然能够操纵术语的描述。但是,我并不想删除所有<cite>标记,而是尝试保留预期的标记。

更新2:我找到了一个相当粗糙的解决方案。我们假设<p>的描述是一些HTML代码段:

onomasticon

我的模块现在将所有块元素转换为具有适当类名的跨度,因此描述变为

<p>Another word for <strong>thesaurus</strong></p>
<p><img src="thesaurus.png" /></p>

这样,我有内联元素,不应该打破短语上下文。添加一些CSS来设置工具提示的样式并使<span class="p">Another word for <strong>thesaurus</strong></span> <span class="p"><img src="thesaurus.png" /></span> 的行为有点像span.p,这一切都归结为此。

&#13;
&#13;
p
&#13;
dfn {
  display: inline-block;
  position: relative;
}
dfn > span {
  display: none;
}
dfn:hover > span {
  display: block;
  position: absolute;
  top: calc(1em + 5px);
  max-width: 20em;
  background: #ccc;
  padding: .5em;
}
dfn img {
  max-width: 12em;
}
dfn > span span.p {
  display: block;
  margin-bottom: .5em;
}
&#13;
&#13;
&#13;

到目前为止,这是我最好看的选项,支持内联元素工具提示的有限HTML。但是,它可能不是最佳选择,因为它需要对HTML块元素进行hacky重写。

更新3: ChristianF的回答非常重要,如何在词汇表术语定义中保留HTML。如果描述不是 in dfn标签中的元素,而是跟随兄弟,我们仍然可以隐藏并显示它,例如使用CSS选择器<p>An <dfn><span><span class="p">Another word for <strong>thesaurus</strong></span> <span class="p"><img src="http://i.imgur.com/G0bl4k7.png" /></span></span></span>onomasticon</dfn> is not a dinosaur.</p>。但是,由于大多数词汇表术语都会在词组上下文中找到,这将再次打破布局,因为段落内不允许使用div。

所以我们需要一个元素,它既可以用在短语上,也可以用包含块元素。根据此beautiful HTML structure diagramdfn + div.dfn-tooltip标记将是唯一合适的标记。

&#13;
&#13;
<button>
&#13;
p {
  display: relative;
}
dfn + .dfn-tooltip {
  display: none;
}
dfn:hover + .dfn-tooltip {
  display: block;
  position: absolute;
  top: 3em;
  max-width: 20em;
  background: #ccc;
  padding: .5em;
  border: none;
}
.dfn-tooltip img {
  max-width: 12em;
}
&#13;
&#13;
&#13;

这看起来很有希望。当然,有两个主要缺点:(1)此处的按钮元素在语义上是不正确的;(2)工具提示在悬停时不会保持打开,因为它不是dfn标签的子元素了。

更新4:进一步避免第二个缺点就是将按钮元素移回dfn标记,因为上下文是相同的。

&#13;
&#13;
<p>An <dfn>onomasticon</dfn><button class="dfn-tooltip"><p>Another word for <strong>thesaurus</strong></p><p><img src="http://i.imgur.com/G0bl4k7.png" /></p></button> is not a dinosaur.</p>
&#13;
dfn {
  position: relative;
  display: inline-block;
}
dfn > .dfn-tooltip {
  display: none;
}
dfn:hover > .dfn-tooltip {
  display: block;
  position: absolute; 
  top: calc(1em + 5px);
  max-width: 20em;
  background: #ccc;
  padding: .5em;
  border: none;
}
.dfn-tooltip img {
  max-width: 12em;
}
&#13;
&#13;
&#13;

更新5(最后):亚当的回答提出了一些很好的技巧来整合标题属性的初衷,将所有内容放在一起,这就是我最终的结果

&#13;
&#13;
<p>An <dfn>onomasticon<button class="dfn-tooltip"><p>Another word for <strong>thesaurus</strong></p><p><img src="http://i.imgur.com/G0bl4k7.png" /></p></button></dfn> is not a dinosaur.</p>
&#13;
dfn {
  position: relative;
  display: inline-block;
  cursor: help;
}
dfn:before {
  content: attr(title);
}
dfn > .dfn-tooltip {
  display: none;
}
dfn:hover > .dfn-tooltip {
  display: block;
  position: absolute; 
  top: calc(1em + 5px);
  max-width: 20em;
  background: #ccc;
  padding: .5em;
  border: none;
  cursor: help;
}
.dfn-tooltip img {
  max-width: 12em;
}
&#13;
&#13;
&#13;

顺便说一下,如果有人感兴趣,我会在名为Onomasticon的模块中使用它,它为Drupal 8提供基本的词汇表功能。

4 个答案:

答案 0 :(得分:2)

正如评论中已经确定的那样,最简单的方法是简单地用其他内容替换p标签。这需要最少量的解决方法,因此最不可能破解的方法。

最快的方法是将开头p标记替换为两个br标记,并将结果替换为空字符串。这样你就会在两个文本块之间得到一个可见的空行,类似于段落中断通常会给你的。大多数情况下,这足以让人产生段落休息的错觉。

正如您所发现的,另一种解决方案是使用span-tags替换它们,并将它们设置为与普通P-tag完全相同的样式。这需要更多的代码和工作,但有行为的好处,嗯...正好像你网站上的段落,创造一个完美的错觉,实际上有一个段落在那里。 如果段落以不寻常的方式设置样式,这是我使用的方法,因此简单的空行不足以创建幻觉。例如,第一行缩进时,第一个字符的特殊样式等等。

在你的情况下,我认为一个简单的双br就足够了。看到你的段落只有.5em底部边距。

编辑,添加: 根据你对我的回答的评论,我还有一个想法。那就是创建一个隐藏的div,并将注释存储在这个中。为其提供与rel标记的dfn属性相对应的ID。然后,使用CSS和JS,在悬停时将DIV设置为工具提示。将需要更多的工作,但它将允许您保留所有格式和标签没有问题 对于那些不支持必要功能的用户,可以在title标签内使用精简版本。然后在显示“增强”工具提示时使用相同的JS来抑制它。

但是,你肯定会在这里使用JS。除非您可以使用CSS3 adjacent sibling selector

答案 1 :(得分:2)

请注意,W3C说:

  

定义术语:如果dfn元素具有title属性,则该属性的确切值是要定义的术语

因此,你可以有一个简单的解决方案,你可以在Matchday属性中定义术语,并在里面定义

&#13;
&#13;
title
&#13;
dfn::before {content: attr(title);padding: 0 0 1em;}      
dfn button {display: none; position: absolute}
dfn:hover button, dfn:focus button {display: block;}
&#13;
&#13;
&#13;

我找不到任何可以替换<p>An <dfn title="onomasticon" tabindex="0"><button disabled> <p>Another word for <strong>thesaurus</strong></p> <p><img src="http://i.imgur.com/G0bl4k7.png" /></p> </button></dfn> is not a dinosaur. </p>元素的标记,这个元素似乎是唯一在这里工作的元素。

因此,我们必须将button属性添加到disabled元素以禁用其button行为(焦点),并在button上设置tabindex元素启用箭头导航。

答案 2 :(得分:0)

我使用了object标签。这对我来说更有意义,因为你在文本中包含了信息。

dfn {
  position: relative;
  display: inline-block;
}
dfn > .dfn-tooltip {
  display: none;
}
dfn:hover > .dfn-tooltip,
.dfn-tooltip:hover {
  display: block;
  position: absolute;
  top: calc(1em + 4px);
  max-width: auto;
  background: #ccc;
  padding: .5em;
  border: none;
}
.dfn-tooltip span {
  max-width: 12em;
  float: left;
}
.dfn-tooltip img {
  max-width: 12em;
  float: left;
  clear: both;
}
<p>An <dfn>onomasticon
  <object class="dfn-tooltip">
    <p>Another word for <strong>thesaurus</strong></p>
    <p><img src="http://i.imgur.com/G0bl4k7.png" /></p>
  </object>
  </dfn> is not a dinosaur.
</p>

答案 3 :(得分:0)

值得研究的另一个解决方案是使用纯css,只与元素结合使用。忘记标题,或者添加它。

如果你有能力生成并使用内联css,并在输出服务之前将其注入头部,那么如何:

The <abbr id="abbr_1" title="Fox is an animal">fox</abbr>. Another <abbr id="abbr_2">word</abbr>

abbr
{
   display: none;
   position: absolute;
   z-index: 1; //probably not required, but I hope the title won't show up above it.... I guess it won't.
}
abbr:hover{display: block;}
#abbr_1:before{
   content: '<p>Fox is a <i class="">beautiful</i> \'animal\'</p>'
}
...etc

不要忘记逃避单引号;)